Merge pull request from GHSA-5h3x-9wvq-w4m2

Co-authored-by: Francisco <fg@frang.io>
Co-authored-by: Ernesto García <ernestognw@gmail.com>
(cherry picked from commit d9474327a4)
This commit is contained in:
Hadrien Croubois
2023-06-07 02:32:14 +02:00
committed by Francisco Giordano
parent fa3a30a580
commit 33ff9b086d
4 changed files with 231 additions and 2 deletions

View File

@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../../contracts/utils/Strings.sol";
import "../../contracts/governance/Governor.sol";
contract GovernorInternalTest is Test, Governor {
constructor() Governor("") {}
function testValidDescriptionForProposer(string memory description, address proposer, bool includeProposer) public {
if (includeProposer) {
description = string.concat(description, "#proposer=", Strings.toHexString(proposer));
}
assertTrue(_isValidDescriptionForProposer(proposer, description));
}
function testInvalidDescriptionForProposer(
string memory description,
address commitProposer,
address actualProposer
) public {
vm.assume(commitProposer != actualProposer);
description = string.concat(description, "#proposer=", Strings.toHexString(commitProposer));
assertFalse(_isValidDescriptionForProposer(actualProposer, description));
}
// We don't need to truly implement implement the missing functions because we are just testing
// internal helpers.
function clock() public pure override returns (uint48) {}
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() public pure override returns (string memory) {}
// solhint-disable-next-line func-name-mixedcase
function COUNTING_MODE() public pure virtual override returns (string memory) {}
function votingDelay() public pure virtual override returns (uint256) {}
function votingPeriod() public pure virtual override returns (uint256) {}
function quorum(uint256) public pure virtual override returns (uint256) {}
function hasVoted(uint256, address) public pure virtual override returns (bool) {}
function _quorumReached(uint256) internal pure virtual override returns (bool) {}
function _voteSucceeded(uint256) internal pure virtual override returns (bool) {}
function _getVotes(address, uint256, bytes memory) internal pure virtual override returns (uint256) {}
function _countVote(uint256, address, uint8, uint256, bytes memory) internal virtual override {}
}

View File

@ -544,6 +544,89 @@ contract('Governor', function (accounts) {
});
});
describe('frontrun protection using description suffix', function () {
describe('without protection', function () {
describe('without suffix', function () {
it('proposer can propose', async function () {
expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated');
});
it('someone else can propose', async function () {
expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated');
});
});
describe('with different suffix', function () {
beforeEach(async function () {
this.proposal = this.helper.setProposal(
[
{
target: this.receiver.address,
data: this.receiver.contract.methods.mockFunction().encodeABI(),
value,
},
],
`<proposal description>#wrong-suffix=${proposer}`,
);
});
it('proposer can propose', async function () {
expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated');
});
it('someone else can propose', async function () {
expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated');
});
});
describe('with proposer suffix but bad address part', function () {
beforeEach(async function () {
this.proposal = this.helper.setProposal(
[
{
target: this.receiver.address,
data: this.receiver.contract.methods.mockFunction().encodeABI(),
value,
},
],
`<proposal description>#proposer=0x3C44CdDdB6a900fa2b585dd299e03d12FA429XYZ`, // XYZ are not a valid hex char
);
});
it('propose can propose', async function () {
expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated');
});
it('someone else can propose', async function () {
expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated');
});
});
});
describe('with protection via proposer suffix', function () {
beforeEach(async function () {
this.proposal = this.helper.setProposal(
[
{
target: this.receiver.address,
data: this.receiver.contract.methods.mockFunction().encodeABI(),
value,
},
],
`<proposal description>#proposer=${proposer}`,
);
});
it('proposer can propose', async function () {
expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated');
});
it('someone else cannot propose', async function () {
await expectRevert(this.helper.propose({ from: voter1 }), 'Governor: proposer restricted');
});
});
});
describe('onlyGovernance updates', function () {
it('setVotingDelay is protected', async function () {
await expectRevert(this.mock.setVotingDelay('0'), 'Governor: onlyGovernance');