Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f28ede6
Add Nonces contract
JulissaDantes Nov 14, 2022
1931d64
Remove permit from erc20votes
JulissaDantes Nov 15, 2022
cc25b3f
Update ERC20Permit contract
JulissaDantes Nov 15, 2022
39bd173
Update Changelog
JulissaDantes Nov 15, 2022
5df3792
Add Nonces dcumentation
JulissaDantes Nov 15, 2022
b9c425f
Update changelog with PR number
JulissaDantes Nov 16, 2022
485a322
Use Votes for ERC20Votes
JulissaDantes Nov 17, 2022
f40bf1c
Remove duplicate tests
JulissaDantes Nov 21, 2022
1c07a94
Fix Votes tests
JulissaDantes Nov 21, 2022
f4baabe
update changelog
JulissaDantes Nov 22, 2022
a7ec549
Update CHANGELOG.md
JulissaDantes Nov 25, 2022
8fab231
Merge branch 'next-v5.0' into refactor/erc20-votes
JulissaDantes Nov 25, 2022
5202e0d
Add test case
JulissaDantes Nov 25, 2022
0a2a857
Update test
JulissaDantes Nov 25, 2022
c140d72
Merge branch 'refactor/erc20-votes' of https://github.com/JulissaDant…
JulissaDantes Nov 25, 2022
cffa45c
Update tests
JulissaDantes Nov 25, 2022
f881aad
Merge branch 'next-v5.0' into refactor/erc20-votes
JulissaDantes Nov 25, 2022
390f04a
Add numCheckpoints
JulissaDantes Nov 28, 2022
b41574c
Add tests to ERC20VotesComp
JulissaDantes Nov 28, 2022
4cda6a0
Update template
JulissaDantes Nov 28, 2022
c2a9537
Update contracts/token/ERC20/extensions/ERC20Votes.sol
JulissaDantes Nov 29, 2022
6adfc96
Update contracts/token/ERC20/extensions/ERC20Votes.sol
JulissaDantes Nov 29, 2022
e31342b
Update contracts/utils/Checkpoints.sol
JulissaDantes Nov 29, 2022
3f001ad
update template
JulissaDantes Nov 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add numCheckpoints
  • Loading branch information
JulissaDantes committed Nov 28, 2022
commit 390f04ad17118acf0dac27a7215b5e2053a32d92
15 changes: 15 additions & 0 deletions contracts/governance/utils/Votes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "../../utils/Nonces.sol";
import "../../utils/Checkpoints.sol";
import "../../utils/cryptography/EIP712.sol";
import "./IVotes.sol";
import "../../utils/math/SafeCast.sol";

/**
* @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be
Expand Down Expand Up @@ -167,6 +168,20 @@ abstract contract Votes is IVotes, Context, EIP712, Nonces {
}
}

/**
* @dev Get number of checkpoints for `account`.
*/
function _numCheckpoints(address account) internal view virtual returns (uint32) {
return SafeCast.toUint32(_delegateCheckpoints[account].length());
}

/**
* @dev Get the `pos`-th checkpoint for `account`.
*/
function _checkpoints(address account, uint32 pos) internal view virtual returns (Checkpoints.Checkpoint memory) {
return _delegateCheckpoints[account].getAtPosition(pos);
}

function _add(uint256 a, uint256 b) private pure returns (uint256) {
return a + b;
}
Expand Down
14 changes: 14 additions & 0 deletions contracts/token/ERC20/extensions/ERC20Votes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ abstract contract ERC20Votes is ERC20, Votes {
super._afterTokenTransfer(from, to, amount);
}

/**
* @dev Get number of checkpoints for `account`.
*/
function numCheckpoints(address account) public view virtual returns (uint32) {
return super._numCheckpoints(account);
}

/**
* @dev Get the `pos`-th checkpoint for `account`.
*/
function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoints.Checkpoint memory) {
return super._checkpoints(account, pos);
}

/**
* @dev Returns the balance of `account`.
*/
Expand Down
8 changes: 8 additions & 0 deletions contracts/utils/Checkpoints.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ library Checkpoints {
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}

/**
* @dev Returns checkpoint at given position.
*/
function getAtPosition(History storage self, uint32 pos) internal view returns (Checkpoint memory) {
Checkpoint storage last = _unsafeAccess(self._checkpoints, pos);
return last;
}

/**
* @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block.
*
Expand Down
49 changes: 49 additions & 0 deletions test/token/ERC20/extensions/ERC20Votes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,55 @@ contract('ERC20Votes', function (accounts) {
await this.token.mint(holder, supply);
});

describe('numCheckpoints', function () {
it('returns the number of checkpoints for a delegate', async function () {
await this.token.transfer(recipient, '100', { from: holder }); //give an account a few tokens for readability
expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0');

const t1 = await this.token.delegate(other1, { from: recipient });
expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1');

const t2 = await this.token.transfer(other2, 10, { from: recipient });
expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2');

const t3 = await this.token.transfer(other2, 10, { from: recipient });
expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('3');

const t4 = await this.token.transfer(recipient, 20, { from: holder });
expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('4');

expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([ t1.receipt.blockNumber.toString(), '100' ]);
expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([ t2.receipt.blockNumber.toString(), '90' ]);
expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([ t3.receipt.blockNumber.toString(), '80' ]);
expect(await this.token.checkpoints(other1, 3)).to.be.deep.equal([ t4.receipt.blockNumber.toString(), '100' ]);

await time.advanceBlock();
expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal('100');
expect(await this.token.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('90');
expect(await this.token.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('80');
expect(await this.token.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('100');
});

it('does not add more than one checkpoint in a block', async function () {
await this.token.transfer(recipient, '100', { from: holder });
expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0');

const [ t1, t2, t3 ] = await batchInBlock([
() => this.token.delegate(other1, { from: recipient, gas: 100000 }),
() => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }),
() => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }),
]);
expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1');
expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([ t1.receipt.blockNumber.toString(), '80' ]);
// expectReve(await this.token.checkpoints(other1, 1)).to.be.deep.equal([ '0', '0' ]); // Reverts due to array overflow check
// expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([ '0', '0' ]); // Reverts due to array overflow check

const t4 = await this.token.transfer(recipient, 20, { from: holder });
expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2');
expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([ t4.receipt.blockNumber.toString(), '100' ]);
});
});

describe('balanceOf', function () {
it('grants to initial account', async function () {
expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('10000000000000000000000000');
Expand Down