Skip to content

Commit ec88e9d

Browse files
Amxxfrangio
authored andcommitted
Add support for EOA target in Governor.relay (#3730)
(cherry picked from commit ed12acf)
1 parent 1679113 commit ec88e9d

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* `ERC165Checker`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339))
88
* `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468))
99
* `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469))
10+
* `Governor`: make the `relay` function payable, and add support for EOA payments. ([#3730](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3730))
1011
* `GovernorCompatibilityBravo`: remove unused `using` statements. ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506))
1112
* `ERC20`: optimize `_transfer`, `_mint` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513))
1213
* `ERC20Votes`, `ERC721Votes`: optimize `getPastVotes` for looking up recent checkpoints. ([#3673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3673))

contracts/governance/Governor.sol

+3-2
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,9 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive
544544
address target,
545545
uint256 value,
546546
bytes calldata data
547-
) external virtual onlyGovernance {
548-
Address.functionCallWithValue(target, data, value);
547+
) external payable virtual onlyGovernance {
548+
(bool success, bytes memory returndata) = target.call{value: value}(data);
549+
Address.verifyCallResult(success, returndata, "Governor: relay reverted without message");
549550
}
550551

551552
/**

test/governance/extensions/GovernorTimelockControl.test.js

+33
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,39 @@ contract('GovernorTimelockControl', function (accounts) {
293293
);
294294
});
295295

296+
it('is payable and can transfer eth to EOA', async function () {
297+
const t2g = web3.utils.toBN(128); // timelock to governor
298+
const g2o = web3.utils.toBN(100); // governor to eoa (other)
299+
300+
this.helper.setProposal([
301+
{
302+
target: this.mock.address,
303+
value: t2g,
304+
data: this.mock.contract.methods.relay(
305+
other,
306+
g2o,
307+
'0x',
308+
).encodeABI(),
309+
},
310+
], '<proposal description>');
311+
312+
expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
313+
const timelockBalance = await web3.eth.getBalance(this.timelock.address).then(web3.utils.toBN);
314+
const otherBalance = await web3.eth.getBalance(other).then(web3.utils.toBN);
315+
316+
await this.helper.propose();
317+
await this.helper.waitForSnapshot();
318+
await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
319+
await this.helper.waitForDeadline();
320+
await this.helper.queue();
321+
await this.helper.waitForEta();
322+
await this.helper.execute();
323+
324+
expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(timelockBalance.sub(t2g));
325+
expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(t2g.sub(g2o));
326+
expect(await web3.eth.getBalance(other)).to.be.bignumber.equal(otherBalance.add(g2o));
327+
});
328+
296329
it('protected against other proposers', async function () {
297330
await this.timelock.schedule(
298331
this.mock.address,

0 commit comments

Comments
 (0)