Add timestamp based governor with EIP-6372 and EIP-5805 (#3934)
Co-authored-by: Francisco Giordano <fg@frang.io> Co-authored-by: Ernesto García <ernestognw@gmail.com> Co-authored-by: Francisco <frangio.1@gmail.com>
This commit is contained in:
@ -6,7 +6,10 @@ const { fromRpcSig } = require('ethereumjs-util');
|
||||
const ethSigUtil = require('eth-sig-util');
|
||||
const Wallet = require('ethereumjs-wallet').default;
|
||||
|
||||
const { shouldBehaveLikeEIP6372 } = require('./EIP6372.behavior');
|
||||
|
||||
const { getDomain, domainType, domainSeparator } = require('../../helpers/eip712');
|
||||
const { clockFromReceipt } = require('../../helpers/time');
|
||||
|
||||
const Delegation = [
|
||||
{ name: 'delegatee', type: 'address' },
|
||||
@ -14,7 +17,9 @@ const Delegation = [
|
||||
{ name: 'expiry', type: 'uint256' },
|
||||
];
|
||||
|
||||
function shouldBehaveLikeVotes() {
|
||||
function shouldBehaveLikeVotes(mode = 'blocknumber') {
|
||||
shouldBehaveLikeEIP6372(mode);
|
||||
|
||||
describe('run votes workflow', function () {
|
||||
it('initial nonce is 0', async function () {
|
||||
expect(await this.votes.nonces(this.account1)).to.be.bignumber.equal('0');
|
||||
@ -57,6 +62,8 @@ function shouldBehaveLikeVotes() {
|
||||
expect(await this.votes.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS);
|
||||
|
||||
const { receipt } = await this.votes.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s);
|
||||
const timepoint = await clockFromReceipt[mode](receipt);
|
||||
|
||||
expectEvent(receipt, 'DelegateChanged', {
|
||||
delegator: delegatorAddress,
|
||||
fromDelegate: ZERO_ADDRESS,
|
||||
@ -71,9 +78,9 @@ function shouldBehaveLikeVotes() {
|
||||
expect(await this.votes.delegates(delegatorAddress)).to.be.equal(delegatorAddress);
|
||||
|
||||
expect(await this.votes.getVotes(delegatorAddress)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastVotes(delegatorAddress, receipt.blockNumber - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastVotes(delegatorAddress, timepoint - 1)).to.be.bignumber.equal('0');
|
||||
await time.advanceBlock();
|
||||
expect(await this.votes.getPastVotes(delegatorAddress, receipt.blockNumber)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastVotes(delegatorAddress, timepoint)).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('rejects reused signature', async function () {
|
||||
@ -157,6 +164,8 @@ function shouldBehaveLikeVotes() {
|
||||
expect(await this.votes.delegates(this.account1)).to.be.equal(ZERO_ADDRESS);
|
||||
|
||||
const { receipt } = await this.votes.delegate(this.account1, { from: this.account1 });
|
||||
const timepoint = await clockFromReceipt[mode](receipt);
|
||||
|
||||
expectEvent(receipt, 'DelegateChanged', {
|
||||
delegator: this.account1,
|
||||
fromDelegate: ZERO_ADDRESS,
|
||||
@ -171,9 +180,9 @@ function shouldBehaveLikeVotes() {
|
||||
expect(await this.votes.delegates(this.account1)).to.be.equal(this.account1);
|
||||
|
||||
expect(await this.votes.getVotes(this.account1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastVotes(this.account1, receipt.blockNumber - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastVotes(this.account1, timepoint - 1)).to.be.bignumber.equal('0');
|
||||
await time.advanceBlock();
|
||||
expect(await this.votes.getPastVotes(this.account1, receipt.blockNumber)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastVotes(this.account1, timepoint)).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('delegation without tokens', async function () {
|
||||
@ -202,6 +211,8 @@ function shouldBehaveLikeVotes() {
|
||||
expect(await this.votes.delegates(this.account1)).to.be.equal(this.account1);
|
||||
|
||||
const { receipt } = await this.votes.delegate(this.account1Delegatee, { from: this.account1 });
|
||||
const timepoint = await clockFromReceipt[mode](receipt);
|
||||
|
||||
expectEvent(receipt, 'DelegateChanged', {
|
||||
delegator: this.account1,
|
||||
fromDelegate: this.account1,
|
||||
@ -217,16 +228,16 @@ function shouldBehaveLikeVotes() {
|
||||
previousBalance: '0',
|
||||
newBalance: '1',
|
||||
});
|
||||
const prevBlock = receipt.blockNumber - 1;
|
||||
|
||||
expect(await this.votes.delegates(this.account1)).to.be.equal(this.account1Delegatee);
|
||||
|
||||
expect(await this.votes.getVotes(this.account1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getVotes(this.account1Delegatee)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastVotes(this.account1, receipt.blockNumber - 1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastVotes(this.account1Delegatee, prevBlock)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastVotes(this.account1, timepoint - 1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastVotes(this.account1Delegatee, timepoint - 1)).to.be.bignumber.equal('0');
|
||||
await time.advanceBlock();
|
||||
expect(await this.votes.getPastVotes(this.account1, receipt.blockNumber)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastVotes(this.account1Delegatee, receipt.blockNumber)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastVotes(this.account1, timepoint)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastVotes(this.account1Delegatee, timepoint)).to.be.bignumber.equal('1');
|
||||
});
|
||||
});
|
||||
|
||||
@ -236,7 +247,7 @@ function shouldBehaveLikeVotes() {
|
||||
});
|
||||
|
||||
it('reverts if block number >= current block', async function () {
|
||||
await expectRevert(this.votes.getPastTotalSupply(5e10), 'block not yet mined');
|
||||
await expectRevert(this.votes.getPastTotalSupply(5e10), 'future lookup');
|
||||
});
|
||||
|
||||
it('returns 0 if there are no checkpoints', async function () {
|
||||
@ -244,22 +255,24 @@ function shouldBehaveLikeVotes() {
|
||||
});
|
||||
|
||||
it('returns the latest block if >= last checkpoint block', async function () {
|
||||
const t1 = await this.votes.$_mint(this.account1, this.NFT0);
|
||||
const { receipt } = await this.votes.$_mint(this.account1, this.NFT0);
|
||||
const timepoint = await clockFromReceipt[mode](receipt);
|
||||
await time.advanceBlock();
|
||||
await time.advanceBlock();
|
||||
|
||||
expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('returns zero if < first checkpoint block', async function () {
|
||||
await time.advanceBlock();
|
||||
const t2 = await this.votes.$_mint(this.account1, this.NFT1);
|
||||
const { receipt } = await this.votes.$_mint(this.account1, this.NFT1);
|
||||
const timepoint = await clockFromReceipt[mode](receipt);
|
||||
await time.advanceBlock();
|
||||
await time.advanceBlock();
|
||||
|
||||
expect(await this.votes.getPastTotalSupply(t2.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t2.receipt.blockNumber + 1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('generally returns the voting balance at the appropriate checkpoint', async function () {
|
||||
@ -279,17 +292,23 @@ function shouldBehaveLikeVotes() {
|
||||
await time.advanceBlock();
|
||||
await time.advanceBlock();
|
||||
|
||||
expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t2.receipt.blockNumber)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t2.receipt.blockNumber + 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t3.receipt.blockNumber)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t3.receipt.blockNumber + 1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t4.receipt.blockNumber)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t4.receipt.blockNumber + 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t5.receipt.blockNumber)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t5.receipt.blockNumber + 1)).to.be.bignumber.equal('1');
|
||||
t1.timepoint = await clockFromReceipt[mode](t1.receipt);
|
||||
t2.timepoint = await clockFromReceipt[mode](t2.receipt);
|
||||
t3.timepoint = await clockFromReceipt[mode](t3.receipt);
|
||||
t4.timepoint = await clockFromReceipt[mode](t4.receipt);
|
||||
t5.timepoint = await clockFromReceipt[mode](t5.receipt);
|
||||
|
||||
expect(await this.votes.getPastTotalSupply(t1.timepoint - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t1.timepoint)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t1.timepoint + 1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t2.timepoint)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t2.timepoint + 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t3.timepoint)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t3.timepoint + 1)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t4.timepoint)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t4.timepoint + 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastTotalSupply(t5.timepoint)).to.be.bignumber.equal('1');
|
||||
expect(await this.votes.getPastTotalSupply(t5.timepoint + 1)).to.be.bignumber.equal('1');
|
||||
});
|
||||
});
|
||||
|
||||
@ -305,7 +324,7 @@ function shouldBehaveLikeVotes() {
|
||||
|
||||
describe('getPastVotes', function () {
|
||||
it('reverts if block number >= current block', async function () {
|
||||
await expectRevert(this.votes.getPastVotes(this.account2, 5e10), 'block not yet mined');
|
||||
await expectRevert(this.votes.getPastVotes(this.account2, 5e10), 'future lookup');
|
||||
});
|
||||
|
||||
it('returns 0 if there are no checkpoints', async function () {
|
||||
@ -313,22 +332,24 @@ function shouldBehaveLikeVotes() {
|
||||
});
|
||||
|
||||
it('returns the latest block if >= last checkpoint block', async function () {
|
||||
const t1 = await this.votes.delegate(this.account2, { from: this.account1 });
|
||||
const { receipt } = await this.votes.delegate(this.account2, { from: this.account1 });
|
||||
const timepoint = await clockFromReceipt[mode](receipt);
|
||||
await time.advanceBlock();
|
||||
await time.advanceBlock();
|
||||
|
||||
const latest = await this.votes.getVotes(this.account2);
|
||||
const nextBlock = t1.receipt.blockNumber + 1;
|
||||
expect(await this.votes.getPastVotes(this.account2, t1.receipt.blockNumber)).to.be.bignumber.equal(latest);
|
||||
expect(await this.votes.getPastVotes(this.account2, nextBlock)).to.be.bignumber.equal(latest);
|
||||
expect(await this.votes.getPastVotes(this.account2, timepoint)).to.be.bignumber.equal(latest);
|
||||
expect(await this.votes.getPastVotes(this.account2, timepoint + 1)).to.be.bignumber.equal(latest);
|
||||
});
|
||||
|
||||
it('returns zero if < first checkpoint block', async function () {
|
||||
await time.advanceBlock();
|
||||
const t1 = await this.votes.delegate(this.account2, { from: this.account1 });
|
||||
const { receipt } = await this.votes.delegate(this.account2, { from: this.account1 });
|
||||
const timepoint = await clockFromReceipt[mode](receipt);
|
||||
await time.advanceBlock();
|
||||
await time.advanceBlock();
|
||||
|
||||
expect(await this.votes.getPastVotes(this.account2, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
|
||||
expect(await this.votes.getPastVotes(this.account2, timepoint - 1)).to.be.bignumber.equal('0');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user