ERC20Votes.test.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /* eslint-disable */
  2. const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers');
  3. const { expect } = require('chai');
  4. const { MAX_UINT256, ZERO_ADDRESS } = constants;
  5. const { fromRpcSig } = require('ethereumjs-util');
  6. const ethSigUtil = require('eth-sig-util');
  7. const Wallet = require('ethereumjs-wallet').default;
  8. const ERC20Votes = artifacts.require('$ERC20Votes');
  9. const { batchInBlock } = require('../../../helpers/txpool');
  10. const { EIP712Domain, domainSeparator } = require('../../../helpers/eip712');
  11. const { getChainId } = require('../../../helpers/chainid');
  12. const Delegation = [
  13. { name: 'delegatee', type: 'address' },
  14. { name: 'nonce', type: 'uint256' },
  15. { name: 'expiry', type: 'uint256' },
  16. ];
  17. contract('ERC20Votes', function (accounts) {
  18. const [ holder, recipient, holderDelegatee, other1, other2 ] = accounts;
  19. const name = 'My Token';
  20. const symbol = 'MTKN';
  21. const version = '1';
  22. const supply = new BN('10000000000000000000000000');
  23. beforeEach(async function () {
  24. this.chainId = await getChainId();
  25. this.token = await ERC20Votes.new(name, symbol, name);
  26. });
  27. it('initial nonce is 0', async function () {
  28. expect(await this.token.nonces(holder)).to.be.bignumber.equal('0');
  29. });
  30. it('domain separator', async function () {
  31. expect(
  32. await this.token.DOMAIN_SEPARATOR(),
  33. ).to.equal(
  34. await domainSeparator({ name, version, chainId: this.chainId, verifyingContract: this.token.address }),
  35. );
  36. });
  37. it('minting restriction', async function () {
  38. const amount = new BN('2').pow(new BN('224'));
  39. await expectRevert(
  40. this.token.$_mint(holder, amount),
  41. 'ERC20Votes: total supply risks overflowing votes',
  42. );
  43. });
  44. it('recent checkpoints', async function () {
  45. await this.token.delegate(holder, { from: holder });
  46. for (let i = 0; i < 6; i++) {
  47. await this.token.$_mint(holder, 1);
  48. }
  49. const block = await web3.eth.getBlockNumber();
  50. expect(await this.token.numCheckpoints(holder)).to.be.bignumber.equal('6');
  51. // recent
  52. expect(await this.token.getPastVotes(holder, block - 1)).to.be.bignumber.equal('5');
  53. // non-recent
  54. expect(await this.token.getPastVotes(holder, block - 6)).to.be.bignumber.equal('0');
  55. });
  56. describe('set delegation', function () {
  57. describe('call', function () {
  58. it('delegation with balance', async function () {
  59. await this.token.$_mint(holder, supply);
  60. expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS);
  61. const { receipt } = await this.token.delegate(holder, { from: holder });
  62. expectEvent(receipt, 'DelegateChanged', {
  63. delegator: holder,
  64. fromDelegate: ZERO_ADDRESS,
  65. toDelegate: holder,
  66. });
  67. expectEvent(receipt, 'DelegateVotesChanged', {
  68. delegate: holder,
  69. previousBalance: '0',
  70. newBalance: supply,
  71. });
  72. expect(await this.token.delegates(holder)).to.be.equal(holder);
  73. expect(await this.token.getVotes(holder)).to.be.bignumber.equal(supply);
  74. expect(await this.token.getPastVotes(holder, receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  75. await time.advanceBlock();
  76. expect(await this.token.getPastVotes(holder, receipt.blockNumber)).to.be.bignumber.equal(supply);
  77. });
  78. it('delegation without balance', async function () {
  79. expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS);
  80. const { receipt } = await this.token.delegate(holder, { from: holder });
  81. expectEvent(receipt, 'DelegateChanged', {
  82. delegator: holder,
  83. fromDelegate: ZERO_ADDRESS,
  84. toDelegate: holder,
  85. });
  86. expectEvent.notEmitted(receipt, 'DelegateVotesChanged');
  87. expect(await this.token.delegates(holder)).to.be.equal(holder);
  88. });
  89. });
  90. describe('with signature', function () {
  91. const delegator = Wallet.generate();
  92. const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString());
  93. const nonce = 0;
  94. const buildData = (chainId, verifyingContract, message) => ({ data: {
  95. primaryType: 'Delegation',
  96. types: { EIP712Domain, Delegation },
  97. domain: { name, version, chainId, verifyingContract },
  98. message,
  99. }});
  100. beforeEach(async function () {
  101. await this.token.$_mint(delegatorAddress, supply);
  102. });
  103. it('accept signed delegation', async function () {
  104. const { v, r, s } = fromRpcSig(ethSigUtil.signTypedMessage(
  105. delegator.getPrivateKey(),
  106. buildData(this.chainId, this.token.address, {
  107. delegatee: delegatorAddress,
  108. nonce,
  109. expiry: MAX_UINT256,
  110. }),
  111. ));
  112. expect(await this.token.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS);
  113. const { receipt } = await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s);
  114. expectEvent(receipt, 'DelegateChanged', {
  115. delegator: delegatorAddress,
  116. fromDelegate: ZERO_ADDRESS,
  117. toDelegate: delegatorAddress,
  118. });
  119. expectEvent(receipt, 'DelegateVotesChanged', {
  120. delegate: delegatorAddress,
  121. previousBalance: '0',
  122. newBalance: supply,
  123. });
  124. expect(await this.token.delegates(delegatorAddress)).to.be.equal(delegatorAddress);
  125. expect(await this.token.getVotes(delegatorAddress)).to.be.bignumber.equal(supply);
  126. expect(await this.token.getPastVotes(delegatorAddress, receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  127. await time.advanceBlock();
  128. expect(await this.token.getPastVotes(delegatorAddress, receipt.blockNumber)).to.be.bignumber.equal(supply);
  129. });
  130. it('rejects reused signature', async function () {
  131. const { v, r, s } = fromRpcSig(ethSigUtil.signTypedMessage(
  132. delegator.getPrivateKey(),
  133. buildData(this.chainId, this.token.address, {
  134. delegatee: delegatorAddress,
  135. nonce,
  136. expiry: MAX_UINT256,
  137. }),
  138. ));
  139. await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s);
  140. await expectRevert(
  141. this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s),
  142. 'ERC20Votes: invalid nonce',
  143. );
  144. });
  145. it('rejects bad delegatee', async function () {
  146. const { v, r, s } = fromRpcSig(ethSigUtil.signTypedMessage(
  147. delegator.getPrivateKey(),
  148. buildData(this.chainId, this.token.address, {
  149. delegatee: delegatorAddress,
  150. nonce,
  151. expiry: MAX_UINT256,
  152. }),
  153. ));
  154. const receipt = await this.token.delegateBySig(holderDelegatee, nonce, MAX_UINT256, v, r, s);
  155. const { args } = receipt.logs.find(({ event }) => event == 'DelegateChanged');
  156. expect(args.delegator).to.not.be.equal(delegatorAddress);
  157. expect(args.fromDelegate).to.be.equal(ZERO_ADDRESS);
  158. expect(args.toDelegate).to.be.equal(holderDelegatee);
  159. });
  160. it('rejects bad nonce', async function () {
  161. const { v, r, s } = fromRpcSig(ethSigUtil.signTypedMessage(
  162. delegator.getPrivateKey(),
  163. buildData(this.chainId, this.token.address, {
  164. delegatee: delegatorAddress,
  165. nonce,
  166. expiry: MAX_UINT256,
  167. }),
  168. ));
  169. await expectRevert(
  170. this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s),
  171. 'ERC20Votes: invalid nonce',
  172. );
  173. });
  174. it('rejects expired permit', async function () {
  175. const expiry = (await time.latest()) - time.duration.weeks(1);
  176. const { v, r, s } = fromRpcSig(ethSigUtil.signTypedMessage(
  177. delegator.getPrivateKey(),
  178. buildData(this.chainId, this.token.address, {
  179. delegatee: delegatorAddress,
  180. nonce,
  181. expiry,
  182. }),
  183. ));
  184. await expectRevert(
  185. this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s),
  186. 'ERC20Votes: signature expired',
  187. );
  188. });
  189. });
  190. });
  191. describe('change delegation', function () {
  192. beforeEach(async function () {
  193. await this.token.$_mint(holder, supply);
  194. await this.token.delegate(holder, { from: holder });
  195. });
  196. it('call', async function () {
  197. expect(await this.token.delegates(holder)).to.be.equal(holder);
  198. const { receipt } = await this.token.delegate(holderDelegatee, { from: holder });
  199. expectEvent(receipt, 'DelegateChanged', {
  200. delegator: holder,
  201. fromDelegate: holder,
  202. toDelegate: holderDelegatee,
  203. });
  204. expectEvent(receipt, 'DelegateVotesChanged', {
  205. delegate: holder,
  206. previousBalance: supply,
  207. newBalance: '0',
  208. });
  209. expectEvent(receipt, 'DelegateVotesChanged', {
  210. delegate: holderDelegatee,
  211. previousBalance: '0',
  212. newBalance: supply,
  213. });
  214. expect(await this.token.delegates(holder)).to.be.equal(holderDelegatee);
  215. expect(await this.token.getVotes(holder)).to.be.bignumber.equal('0');
  216. expect(await this.token.getVotes(holderDelegatee)).to.be.bignumber.equal(supply);
  217. expect(await this.token.getPastVotes(holder, receipt.blockNumber - 1)).to.be.bignumber.equal(supply);
  218. expect(await this.token.getPastVotes(holderDelegatee, receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  219. await time.advanceBlock();
  220. expect(await this.token.getPastVotes(holder, receipt.blockNumber)).to.be.bignumber.equal('0');
  221. expect(await this.token.getPastVotes(holderDelegatee, receipt.blockNumber)).to.be.bignumber.equal(supply);
  222. });
  223. });
  224. describe('transfers', function () {
  225. beforeEach(async function () {
  226. await this.token.$_mint(holder, supply);
  227. });
  228. it('no delegation', async function () {
  229. const { receipt } = await this.token.transfer(recipient, 1, { from: holder });
  230. expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' });
  231. expectEvent.notEmitted(receipt, 'DelegateVotesChanged');
  232. this.holderVotes = '0';
  233. this.recipientVotes = '0';
  234. });
  235. it('sender delegation', async function () {
  236. await this.token.delegate(holder, { from: holder });
  237. const { receipt } = await this.token.transfer(recipient, 1, { from: holder });
  238. expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' });
  239. expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, previousBalance: supply, newBalance: supply.subn(1) });
  240. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  241. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  242. this.holderVotes = supply.subn(1);
  243. this.recipientVotes = '0';
  244. });
  245. it('receiver delegation', async function () {
  246. await this.token.delegate(recipient, { from: recipient });
  247. const { receipt } = await this.token.transfer(recipient, 1, { from: holder });
  248. expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' });
  249. expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' });
  250. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  251. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  252. this.holderVotes = '0';
  253. this.recipientVotes = '1';
  254. });
  255. it('full delegation', async function () {
  256. await this.token.delegate(holder, { from: holder });
  257. await this.token.delegate(recipient, { from: recipient });
  258. const { receipt } = await this.token.transfer(recipient, 1, { from: holder });
  259. expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' });
  260. expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, previousBalance: supply, newBalance: supply.subn(1) });
  261. expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' });
  262. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  263. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  264. this.holderVotes = supply.subn(1);
  265. this.recipientVotes = '1';
  266. });
  267. afterEach(async function () {
  268. expect(await this.token.getVotes(holder)).to.be.bignumber.equal(this.holderVotes);
  269. expect(await this.token.getVotes(recipient)).to.be.bignumber.equal(this.recipientVotes);
  270. // need to advance 2 blocks to see the effect of a transfer on "getPastVotes"
  271. const blockNumber = await time.latestBlock();
  272. await time.advanceBlock();
  273. expect(await this.token.getPastVotes(holder, blockNumber)).to.be.bignumber.equal(this.holderVotes);
  274. expect(await this.token.getPastVotes(recipient, blockNumber)).to.be.bignumber.equal(this.recipientVotes);
  275. });
  276. });
  277. // The following tests are a adaptation of https://github.com/compound-finance/compound-protocol/blob/master/tests/Governance/CompTest.js.
  278. describe('Compound test suite', function () {
  279. beforeEach(async function () {
  280. await this.token.$_mint(holder, supply);
  281. });
  282. describe('balanceOf', function () {
  283. it('grants to initial account', async function () {
  284. expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('10000000000000000000000000');
  285. });
  286. });
  287. describe('numCheckpoints', function () {
  288. it('returns the number of checkpoints for a delegate', async function () {
  289. await this.token.transfer(recipient, '100', { from: holder }); //give an account a few tokens for readability
  290. expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0');
  291. const t1 = await this.token.delegate(other1, { from: recipient });
  292. expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1');
  293. const t2 = await this.token.transfer(other2, 10, { from: recipient });
  294. expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2');
  295. const t3 = await this.token.transfer(other2, 10, { from: recipient });
  296. expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('3');
  297. const t4 = await this.token.transfer(recipient, 20, { from: holder });
  298. expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('4');
  299. expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([ t1.receipt.blockNumber.toString(), '100' ]);
  300. expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([ t2.receipt.blockNumber.toString(), '90' ]);
  301. expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([ t3.receipt.blockNumber.toString(), '80' ]);
  302. expect(await this.token.checkpoints(other1, 3)).to.be.deep.equal([ t4.receipt.blockNumber.toString(), '100' ]);
  303. await time.advanceBlock();
  304. expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal('100');
  305. expect(await this.token.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('90');
  306. expect(await this.token.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('80');
  307. expect(await this.token.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('100');
  308. });
  309. it('does not add more than one checkpoint in a block', async function () {
  310. await this.token.transfer(recipient, '100', { from: holder });
  311. expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0');
  312. const [ t1, t2, t3 ] = await batchInBlock([
  313. () => this.token.delegate(other1, { from: recipient, gas: 100000 }),
  314. () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }),
  315. () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }),
  316. ]);
  317. expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1');
  318. expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([ t1.receipt.blockNumber.toString(), '80' ]);
  319. // expectReve(await this.token.checkpoints(other1, 1)).to.be.deep.equal([ '0', '0' ]); // Reverts due to array overflow check
  320. // expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([ '0', '0' ]); // Reverts due to array overflow check
  321. const t4 = await this.token.transfer(recipient, 20, { from: holder });
  322. expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2');
  323. expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([ t4.receipt.blockNumber.toString(), '100' ]);
  324. });
  325. });
  326. describe('getPastVotes', function () {
  327. it('reverts if block number >= current block', async function () {
  328. await expectRevert(
  329. this.token.getPastVotes(other1, 5e10),
  330. 'ERC20Votes: block not yet mined',
  331. );
  332. });
  333. it('returns 0 if there are no checkpoints', async function () {
  334. expect(await this.token.getPastVotes(other1, 0)).to.be.bignumber.equal('0');
  335. });
  336. it('returns the latest block if >= last checkpoint block', async function () {
  337. const t1 = await this.token.delegate(other1, { from: holder });
  338. await time.advanceBlock();
  339. await time.advanceBlock();
  340. expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal('10000000000000000000000000');
  341. expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal('10000000000000000000000000');
  342. });
  343. it('returns zero if < first checkpoint block', async function () {
  344. await time.advanceBlock();
  345. const t1 = await this.token.delegate(other1, { from: holder });
  346. await time.advanceBlock();
  347. await time.advanceBlock();
  348. expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  349. expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal('10000000000000000000000000');
  350. });
  351. it('generally returns the voting balance at the appropriate checkpoint', async function () {
  352. const t1 = await this.token.delegate(other1, { from: holder });
  353. await time.advanceBlock();
  354. await time.advanceBlock();
  355. const t2 = await this.token.transfer(other2, 10, { from: holder });
  356. await time.advanceBlock();
  357. await time.advanceBlock();
  358. const t3 = await this.token.transfer(other2, 10, { from: holder });
  359. await time.advanceBlock();
  360. await time.advanceBlock();
  361. const t4 = await this.token.transfer(holder, 20, { from: other2 });
  362. await time.advanceBlock();
  363. await time.advanceBlock();
  364. expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  365. expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal('10000000000000000000000000');
  366. expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal('10000000000000000000000000');
  367. expect(await this.token.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('9999999999999999999999990');
  368. expect(await this.token.getPastVotes(other1, t2.receipt.blockNumber + 1)).to.be.bignumber.equal('9999999999999999999999990');
  369. expect(await this.token.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('9999999999999999999999980');
  370. expect(await this.token.getPastVotes(other1, t3.receipt.blockNumber + 1)).to.be.bignumber.equal('9999999999999999999999980');
  371. expect(await this.token.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('10000000000000000000000000');
  372. expect(await this.token.getPastVotes(other1, t4.receipt.blockNumber + 1)).to.be.bignumber.equal('10000000000000000000000000');
  373. });
  374. });
  375. });
  376. describe('getPastTotalSupply', function () {
  377. beforeEach(async function () {
  378. await this.token.delegate(holder, { from: holder });
  379. });
  380. it('reverts if block number >= current block', async function () {
  381. await expectRevert(
  382. this.token.getPastTotalSupply(5e10),
  383. 'ERC20Votes: block not yet mined',
  384. );
  385. });
  386. it('returns 0 if there are no checkpoints', async function () {
  387. expect(await this.token.getPastTotalSupply(0)).to.be.bignumber.equal('0');
  388. });
  389. it('returns the latest block if >= last checkpoint block', async function () {
  390. t1 = await this.token.$_mint(holder, supply);
  391. await time.advanceBlock();
  392. await time.advanceBlock();
  393. expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber)).to.be.bignumber.equal(supply);
  394. expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal(supply);
  395. });
  396. it('returns zero if < first checkpoint block', async function () {
  397. await time.advanceBlock();
  398. const t1 = await this.token.$_mint(holder, supply);
  399. await time.advanceBlock();
  400. await time.advanceBlock();
  401. expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  402. expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal('10000000000000000000000000');
  403. });
  404. it('generally returns the voting balance at the appropriate checkpoint', async function () {
  405. const t1 = await this.token.$_mint(holder, supply);
  406. await time.advanceBlock();
  407. await time.advanceBlock();
  408. const t2 = await this.token.$_burn(holder, 10);
  409. await time.advanceBlock();
  410. await time.advanceBlock();
  411. const t3 = await this.token.$_burn(holder, 10);
  412. await time.advanceBlock();
  413. await time.advanceBlock();
  414. const t4 = await this.token.$_mint(holder, 20);
  415. await time.advanceBlock();
  416. await time.advanceBlock();
  417. expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  418. expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber)).to.be.bignumber.equal('10000000000000000000000000');
  419. expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal('10000000000000000000000000');
  420. expect(await this.token.getPastTotalSupply(t2.receipt.blockNumber)).to.be.bignumber.equal('9999999999999999999999990');
  421. expect(await this.token.getPastTotalSupply(t2.receipt.blockNumber + 1)).to.be.bignumber.equal('9999999999999999999999990');
  422. expect(await this.token.getPastTotalSupply(t3.receipt.blockNumber)).to.be.bignumber.equal('9999999999999999999999980');
  423. expect(await this.token.getPastTotalSupply(t3.receipt.blockNumber + 1)).to.be.bignumber.equal('9999999999999999999999980');
  424. expect(await this.token.getPastTotalSupply(t4.receipt.blockNumber)).to.be.bignumber.equal('10000000000000000000000000');
  425. expect(await this.token.getPastTotalSupply(t4.receipt.blockNumber + 1)).to.be.bignumber.equal('10000000000000000000000000');
  426. });
  427. });
  428. });