Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64e48203ce | |||
| b66fe1606a | |||
| 8fb5f5774e | |||
| 67b2572c6a | |||
| 4337192dc0 | |||
| 41c7b25a65 | |||
| e15862f289 |
@ -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))
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
18
contracts/mocks/ERC165/ERC165ReturnBomb.sol
Normal file
18
contracts/mocks/ERC165/ERC165ReturnBomb.sol
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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
4
package-lock.json
generated
@ -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"
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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));
|
||||
});
|
||||
@ -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
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user