ERC721Votes.test.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /* eslint-disable */
  2. const { BN, 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. this.name = 'My Vote';
  9. const symbol = 'MTKN';
  10. beforeEach(async function () {
  11. this.votes = await ERC721VotesMock.new(name, symbol);
  12. // We get the chain id from the contract because Ganache (used for coverage) does not return the same chain id
  13. // from within the EVM as from the JSON RPC interface.
  14. // See https://github.com/trufflesuite/ganache-core/issues/515
  15. this.chainId = await this.votes.getChainId();
  16. this.token0 = new BN('10000000000000000000000000');
  17. this.token1 = new BN('10');
  18. this.token2 = new BN('20');
  19. this.token3 = new BN('30');
  20. });
  21. describe('balanceOf', function () {
  22. beforeEach(async function () {
  23. await this.votes.mint(account1, this.token0);
  24. await this.votes.mint(account1, this.token1);
  25. await this.votes.mint(account1, this.token2);
  26. await this.votes.mint(account1, this.token3);
  27. });
  28. it('grants to initial account', async function () {
  29. expect(await this.votes.balanceOf(account1)).to.be.bignumber.equal('4');
  30. });
  31. });
  32. describe('transfers', function () {
  33. beforeEach(async function () {
  34. await this.votes.mint(account1, this.token0);
  35. });
  36. it('no delegation', async function () {
  37. const { receipt } = await this.votes.transferFrom(account1, account2, this.token0, { from: account1 });
  38. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.token0 });
  39. expectEvent.notEmitted(receipt, 'DelegateVotesChanged');
  40. this.account1Votes = '0';
  41. this.account2Votes = '0';
  42. });
  43. it('sender delegation', async function () {
  44. await this.votes.delegate(account1, { from: account1 });
  45. const { receipt } = await this.votes.transferFrom(account1, account2, this.token0, { from: account1 });
  46. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.token0 });
  47. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0' });
  48. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  49. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  50. this.account1Votes = '0';
  51. this.account2Votes = '0';
  52. });
  53. it('receiver delegation', async function () {
  54. await this.votes.delegate(account2, { from: account2 });
  55. const { receipt } = await this.votes.transferFrom(account1, account2, this.token0, { from: account1 });
  56. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.token0 });
  57. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousBalance: '0', newBalance: '1' });
  58. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  59. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  60. this.account1Votes = '0';
  61. this.account2Votes = '1';
  62. });
  63. it('full delegation', async function () {
  64. await this.votes.delegate(account1, { from: account1 });
  65. await this.votes.delegate(account2, { from: account2 });
  66. const { receipt } = await this.votes.transferFrom(account1, account2, this.token0, { from: account1 });
  67. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.token0 });
  68. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0'});
  69. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousBalance: '0', newBalance: '1' });
  70. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  71. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  72. this.account1Votes = '0';
  73. this.account2Votes = '1';
  74. });
  75. it('returns the same total supply on transfers', async function () {
  76. await this.votes.delegate(account1, { from: account1 });
  77. const { receipt } = await this.votes.transferFrom(account1, account2, this.token0, { from: account1 });
  78. await time.advanceBlock();
  79. await time.advanceBlock();
  80. expect(await this.votes.getPastTotalSupply(receipt.blockNumber - 1)).to.be.bignumber.equal('1');
  81. expect(await this.votes.getPastTotalSupply(receipt.blockNumber + 1)).to.be.bignumber.equal('1');
  82. this.account1Votes = '0';
  83. this.account2Votes = '0';
  84. });
  85. it('generally returns the voting balance at the appropriate checkpoint', async function () {
  86. await this.votes.mint(account1, this.token1);
  87. await this.votes.mint(account1, this.token2);
  88. await this.votes.mint(account1, this.token3);
  89. const total = await this.votes.balanceOf(account1);
  90. const t1 = await this.votes.delegate(other1, { from: account1 });
  91. await time.advanceBlock();
  92. await time.advanceBlock();
  93. const t2 = await this.votes.transferFrom(account1, other2, this.token0, { from: account1 });
  94. await time.advanceBlock();
  95. await time.advanceBlock();
  96. const t3 = await this.votes.transferFrom(account1, other2, this.token2, { from: account1 });
  97. await time.advanceBlock();
  98. await time.advanceBlock();
  99. const t4 = await this.votes.transferFrom(other2, account1, this.token2, { from: other2 });
  100. await time.advanceBlock();
  101. await time.advanceBlock();
  102. expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  103. expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal(total);
  104. expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal(total);
  105. expect(await this.votes.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('3');
  106. expect(await this.votes.getPastVotes(other1, t2.receipt.blockNumber + 1)).to.be.bignumber.equal('3');
  107. expect(await this.votes.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('2');
  108. expect(await this.votes.getPastVotes(other1, t3.receipt.blockNumber + 1)).to.be.bignumber.equal('2');
  109. expect(await this.votes.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('3');
  110. expect(await this.votes.getPastVotes(other1, t4.receipt.blockNumber + 1)).to.be.bignumber.equal('3');
  111. this.account1Votes = '0';
  112. this.account2Votes = '0';
  113. });
  114. afterEach(async function () {
  115. expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(this.account1Votes);
  116. expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(this.account2Votes);
  117. // need to advance 2 blocks to see the effect of a transfer on "getPastVotes"
  118. const blockNumber = await time.latestBlock();
  119. await time.advanceBlock();
  120. expect(await this.votes.getPastVotes(account1, blockNumber)).to.be.bignumber.equal(this.account1Votes);
  121. expect(await this.votes.getPastVotes(account2, blockNumber)).to.be.bignumber.equal(this.account2Votes);
  122. });
  123. });
  124. describe('Voting workflow', function () {
  125. beforeEach(async function () {
  126. this.account1 = account1;
  127. this.account1Delegatee = account1Delegatee;
  128. this.account2 = account2;
  129. this.name = 'My Vote';
  130. });
  131. shouldBehaveLikeVotes();
  132. });
  133. });