Compare commits

..

7 Commits

Author SHA1 Message Date
64e48203ce 4.7.2 2022-07-27 16:54:01 -03:00
b66fe1606a Update changelog
(cherry picked from commit ffb0ae76e3)
2022-07-27 16:46:00 -03:00
8fb5f5774e Avoid returnbomb in ERC165Checker (#3587)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
(cherry picked from commit dc4869eb23)
2022-07-27 16:45:55 -03:00
67b2572c6a Keep track of historical quorum values (#3561)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
(cherry picked from commit 8ea1fc87c9)
2022-07-27 13:40:16 -03:00
4337192dc0 Fix arbitrum L1 to L2 crosschain call detection (#3578)
* Fix arbitrum L1 to L2 crosschain call detection

* fix BridgeArbitrumL2Mock

* update changelog

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
(cherry picked from commit 81336aefb5)
2022-07-26 15:45:22 -03:00
41c7b25a65 Fix error in documentation and typo (#3567)
(cherry picked from commit 0ccfd2dbd3)
2022-07-21 12:55:33 -03:00
e15862f289 Remove test for feature not in 4.7 2022-07-20 10:52:34 -03:00
13 changed files with 117 additions and 34 deletions

View File

@ -1,5 +1,11 @@
# Changelog
## 4.7.2 (2022-07-27)
* `LibArbitrumL2`, `CrossChainEnabledArbitrumL2`: Fixed detection of cross-chain calls for EOAs. Previously, calls from EOAs would be classified as cross-chain calls. ([#3578](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3578))
* `GovernorVotesQuorumFraction`: Fixed quorum updates so they do not affect past proposals that failed due to lack of quorum. ([#3561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3561))
* `ERC165Checker`: Added protection against large returndata. ([#3587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3587))
## 4.7.1 (2022-07-19)
* `SignatureChecker`: Fix an issue that causes `isValidSignatureNow` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552))

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/arbitrum/LibArbitrumL2.sol)
// OpenZeppelin Contracts (last updated v4.7.2) (crosschain/arbitrum/LibArbitrumL2.sol)
pragma solidity ^0.8.4;
@ -21,7 +21,7 @@ library LibArbitrumL2 {
address public constant ARBSYS = 0x0000000000000000000000000000000000000064;
function isCrossChain(address arbsys) internal view returns (bool) {
return ArbitrumL2_Bridge(arbsys).isTopLevelCall();
return ArbitrumL2_Bridge(arbsys).wasMyCallersAddressAliased();
}
/**
@ -35,9 +35,6 @@ library LibArbitrumL2 {
function crossChainSender(address arbsys) internal view returns (address) {
if (!isCrossChain(arbsys)) revert NotCrossChainCall();
return
ArbitrumL2_Bridge(arbsys).wasMyCallersAddressAliased()
? ArbitrumL2_Bridge(arbsys).myCallersAddressWithoutAliasing()
: msg.sender;
return ArbitrumL2_Bridge(arbsys).myCallersAddressWithoutAliasing();
}
}

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (governance/Governor.sol)
// OpenZeppelin Contracts (last updated v4.7.2) (governance/Governor.sol)
pragma solidity ^0.8.0;
@ -120,7 +120,7 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive
/**
* @dev See {IGovernor-hashProposal}.
*
* The proposal id is produced by hashing the RLC encoded `targets` array, the `values` array, the `calldatas` array
* The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array
* and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id
* can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in
* advance, before the proposal is submitted.

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (governance/IGovernor.sol)
// OpenZeppelin Contracts (last updated v4.7.2) (governance/IGovernor.sol)
pragma solidity ^0.8.0;
@ -141,7 +141,7 @@ abstract contract IGovernor is IERC165 {
/**
* @notice module:user-config
* @dev Delay, in number of block, between the proposal is created and the vote starts. This can be increassed to
* leave time for users to buy voting power, of delegate it, before the voting of a proposal starts.
* leave time for users to buy voting power, or delegate it, before the voting of a proposal starts.
*/
function votingDelay() public view virtual returns (uint256);

View File

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (governance/extensions/GovernorVotesQuorumFraction.sol)
// OpenZeppelin Contracts (last updated v4.7.2) (governance/extensions/GovernorVotesQuorumFraction.sol)
pragma solidity ^0.8.0;
import "./GovernorVotes.sol";
import "../../utils/Checkpoints.sol";
import "../../utils/math/SafeCast.sol";
/**
* @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a
@ -12,7 +14,10 @@ import "./GovernorVotes.sol";
* _Available since v4.3._
*/
abstract contract GovernorVotesQuorumFraction is GovernorVotes {
uint256 private _quorumNumerator;
using Checkpoints for Checkpoints.History;
uint256 private _quorumNumerator; // DEPRECATED
Checkpoints.History private _quorumNumeratorHistory;
event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator);
@ -31,7 +36,27 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes {
* @dev Returns the current quorum numerator. See {quorumDenominator}.
*/
function quorumNumerator() public view virtual returns (uint256) {
return _quorumNumerator;
return _quorumNumeratorHistory._checkpoints.length == 0 ? _quorumNumerator : _quorumNumeratorHistory.latest();
}
/**
* @dev Returns the quorum numerator at a specific block number. See {quorumDenominator}.
*/
function quorumNumerator(uint256 blockNumber) public view virtual returns (uint256) {
// If history is empty, fallback to old storage
uint256 length = _quorumNumeratorHistory._checkpoints.length;
if (length == 0) {
return _quorumNumerator;
}
// Optimistic search, check the latest checkpoint
Checkpoints.Checkpoint memory latest = _quorumNumeratorHistory._checkpoints[length - 1];
if (latest._blockNumber <= blockNumber) {
return latest._value;
}
// Otherwize, do the binary search
return _quorumNumeratorHistory.getAtBlock(blockNumber);
}
/**
@ -45,7 +70,7 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes {
* @dev Returns the quorum for a block number, in terms of number of votes: `supply * numerator / denominator`.
*/
function quorum(uint256 blockNumber) public view virtual override returns (uint256) {
return (token.getPastTotalSupply(blockNumber) * quorumNumerator()) / quorumDenominator();
return (token.getPastTotalSupply(blockNumber) * quorumNumerator(blockNumber)) / quorumDenominator();
}
/**
@ -77,8 +102,17 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes {
"GovernorVotesQuorumFraction: quorumNumerator over quorumDenominator"
);
uint256 oldQuorumNumerator = _quorumNumerator;
_quorumNumerator = newQuorumNumerator;
uint256 oldQuorumNumerator = quorumNumerator();
// Make sure we keep track of the original numerator in contracts upgraded from a version without checkpoints.
if (oldQuorumNumerator != 0 && _quorumNumeratorHistory._checkpoints.length == 0) {
_quorumNumeratorHistory._checkpoints.push(
Checkpoints.Checkpoint({_blockNumber: 0, _value: SafeCast.toUint224(oldQuorumNumerator)})
);
}
// Set new quorum for future proposals
_quorumNumeratorHistory.push(newQuorumNumerator);
emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator);
}

View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
contract ERC165ReturnBombMock is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
if (interfaceId == type(IERC165).interfaceId) {
assembly {
mstore(0, 1)
}
}
assembly {
return(0, 101500)
}
}
}

View File

@ -70,14 +70,10 @@ contract BridgeArbitrumL1Outbox {
}
contract BridgeArbitrumL2Mock is BaseRelayMock {
function isTopLevelCall() public view returns (bool) {
function wasMyCallersAddressAliased() public view returns (bool) {
return _currentSender != address(0);
}
function wasMyCallersAddressAliased() public pure returns (bool) {
return true;
}
function myCallersAddressWithoutAliasing() public view returns (address) {
return _currentSender;
}

View File

@ -1,7 +1,7 @@
{
"name": "@openzeppelin/contracts",
"description": "Secure Smart Contract library for Solidity",
"version": "4.7.1",
"version": "4.7.2",
"files": [
"**/*.sol",
"/build/contracts/*.json",

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.1) (utils/introspection/ERC165Checker.sol)
// OpenZeppelin Contracts (last updated v4.7.2) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.0;
@ -105,9 +105,19 @@ library ERC165Checker {
* Interface identification is specified in ERC-165.
*/
function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
(bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);
if (result.length < 32) return false;
return success && abi.decode(result, (uint256)) > 0;
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "openzeppelin-solidity",
"version": "4.7.1",
"version": "4.7.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "openzeppelin-solidity",
"version": "4.7.1",
"version": "4.7.2",
"license": "MIT",
"bin": {
"openzeppelin-contracts-migrate-imports": "scripts/migrate-imports.js"

View File

@ -1,7 +1,7 @@
{
"name": "openzeppelin-solidity",
"description": "Secure Smart Contract library for Solidity",
"version": "4.7.1",
"version": "4.7.2",
"files": [
"/contracts/**/*.sol",
"/build/contracts/*.json",

View File

@ -104,6 +104,13 @@ contract('GovernorVotesQuorumFraction', function (accounts) {
expect(await this.mock.quorumNumerator()).to.be.bignumber.equal(newRatio);
expect(await this.mock.quorumDenominator()).to.be.bignumber.equal('100');
// it takes one block for the new quorum to take effect
expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1))))
.to.be.bignumber.equal(tokenSupply.mul(ratio).divn(100));
await time.advanceBlock();
expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1))))
.to.be.bignumber.equal(tokenSupply.mul(newRatio).divn(100));
});

View File

@ -7,6 +7,7 @@ const ERC165MissingData = artifacts.require('ERC165MissingData');
const ERC165MaliciousData = artifacts.require('ERC165MaliciousData');
const ERC165NotSupported = artifacts.require('ERC165NotSupported');
const ERC165InterfacesSupported = artifacts.require('ERC165InterfacesSupported');
const ERC165ReturnBombMock = artifacts.require('ERC165ReturnBombMock');
const DUMMY_ID = '0xdeadbeef';
const DUMMY_ID_2 = '0xcafebabe';
@ -72,11 +73,6 @@ contract('ERC165Checker', function (accounts) {
expect(supported.length).to.equal(1);
expect(supported[0]).to.equal(false);
});
it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () {
const supported = await this.mock.supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID);
expect(supported).to.equal(true);
});
});
context('ERC165 not supported', function () {
@ -248,4 +244,23 @@ contract('ERC165Checker', function (accounts) {
expect(supported[0]).to.equal(false);
});
});
it('Return bomb resistance', async function () {
this.target = await ERC165ReturnBombMock.new();
const tx1 = await this.mock.supportsInterface.sendTransaction(this.target.address, DUMMY_ID);
expect(tx1.receipt.gasUsed).to.be.lessThan(120000); // 3*30k + 21k + some margin
const tx2 = await this.mock.getSupportedInterfaces.sendTransaction(
this.target.address,
[
DUMMY_ID,
DUMMY_ID_2,
DUMMY_ID_3,
DUMMY_UNSUPPORTED_ID,
DUMMY_UNSUPPORTED_ID_2,
],
);
expect(tx2.receipt.gasUsed).to.be.lessThan(250000); // (2+5)*30k + 21k + some margin
});
});