Skip to content

Commit 5843c07

Browse files
Transpile 6b9fbb1
1 parent e2bcd07 commit 5843c07

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

contracts/governance/extensions/GovernorVotesQuorumFractionUpgradeable.sol

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
pragma solidity ^0.8.0;
55

66
import "./GovernorVotesUpgradeable.sol";
7+
import "../../utils/CheckpointsUpgradeable.sol";
8+
import "../../utils/math/SafeCastUpgradeable.sol";
79
import "../../proxy/utils/Initializable.sol";
810

911
/**
@@ -13,7 +15,10 @@ import "../../proxy/utils/Initializable.sol";
1315
* _Available since v4.3._
1416
*/
1517
abstract contract GovernorVotesQuorumFractionUpgradeable is Initializable, GovernorVotesUpgradeable {
16-
uint256 private _quorumNumerator;
18+
using CheckpointsUpgradeable for CheckpointsUpgradeable.History;
19+
20+
uint256 private _quorumNumerator; // DEPRECATED
21+
CheckpointsUpgradeable.History private _quorumNumeratorHistory;
1722

1823
event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator);
1924

@@ -36,7 +41,27 @@ abstract contract GovernorVotesQuorumFractionUpgradeable is Initializable, Gover
3641
* @dev Returns the current quorum numerator. See {quorumDenominator}.
3742
*/
3843
function quorumNumerator() public view virtual returns (uint256) {
39-
return _quorumNumerator;
44+
return _quorumNumeratorHistory._checkpoints.length == 0 ? _quorumNumerator : _quorumNumeratorHistory.latest();
45+
}
46+
47+
/**
48+
* @dev Returns the quorum numerator at a specific block number. See {quorumDenominator}.
49+
*/
50+
function quorumNumerator(uint256 blockNumber) public view virtual returns (uint256) {
51+
// If history is empty, fallback to old storage
52+
uint256 length = _quorumNumeratorHistory._checkpoints.length;
53+
if (length == 0) {
54+
return _quorumNumerator;
55+
}
56+
57+
// Optimistic search, check the latest checkpoint
58+
CheckpointsUpgradeable.Checkpoint memory latest = _quorumNumeratorHistory._checkpoints[length - 1];
59+
if (latest._blockNumber <= blockNumber) {
60+
return latest._value;
61+
}
62+
63+
// Otherwize, do the binary search
64+
return _quorumNumeratorHistory.getAtBlock(blockNumber);
4065
}
4166

4267
/**
@@ -50,7 +75,7 @@ abstract contract GovernorVotesQuorumFractionUpgradeable is Initializable, Gover
5075
* @dev Returns the quorum for a block number, in terms of number of votes: `supply * numerator / denominator`.
5176
*/
5277
function quorum(uint256 blockNumber) public view virtual override returns (uint256) {
53-
return (token.getPastTotalSupply(blockNumber) * quorumNumerator()) / quorumDenominator();
78+
return (token.getPastTotalSupply(blockNumber) * quorumNumerator(blockNumber)) / quorumDenominator();
5479
}
5580

5681
/**
@@ -82,8 +107,17 @@ abstract contract GovernorVotesQuorumFractionUpgradeable is Initializable, Gover
82107
"GovernorVotesQuorumFraction: quorumNumerator over quorumDenominator"
83108
);
84109

85-
uint256 oldQuorumNumerator = _quorumNumerator;
86-
_quorumNumerator = newQuorumNumerator;
110+
uint256 oldQuorumNumerator = quorumNumerator();
111+
112+
// Make sure we keep track of the original numerator in contracts upgraded from a version without checkpoints.
113+
if (oldQuorumNumerator != 0 && _quorumNumeratorHistory._checkpoints.length == 0) {
114+
_quorumNumeratorHistory._checkpoints.push(
115+
CheckpointsUpgradeable.Checkpoint({_blockNumber: 0, _value: SafeCastUpgradeable.toUint224(oldQuorumNumerator)})
116+
);
117+
}
118+
119+
// Set new quorum for future proposals
120+
_quorumNumeratorHistory.push(newQuorumNumerator);
87121

88122
emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator);
89123
}
@@ -93,5 +127,5 @@ abstract contract GovernorVotesQuorumFractionUpgradeable is Initializable, Gover
93127
* variables without shifting down storage in the inheritance chain.
94128
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
95129
*/
96-
uint256[49] private __gap;
130+
uint256[48] private __gap;
97131
}

test/governance/extensions/GovernorWeightQuorumFraction.test.js renamed to test/governance/extensions/GovernorVotesQuorumFraction.test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ contract('GovernorVotesQuorumFraction', function (accounts) {
104104

105105
expect(await this.mock.quorumNumerator()).to.be.bignumber.equal(newRatio);
106106
expect(await this.mock.quorumDenominator()).to.be.bignumber.equal('100');
107+
108+
// it takes one block for the new quorum to take effect
109+
expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1))))
110+
.to.be.bignumber.equal(tokenSupply.mul(ratio).divn(100));
111+
112+
await time.advanceBlock();
113+
107114
expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1))))
108115
.to.be.bignumber.equal(tokenSupply.mul(newRatio).divn(100));
109116
});

0 commit comments

Comments
 (0)