ERC721Votes.test.js 7.6 KB

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