Add deployed block numbers to indexable contracts (#2672)

Fixes #2004
pull/2736/head
Yorke Rhodes 1 year ago
parent 2b7ecfc312
commit 467e01a6c7
No known key found for this signature in database
GPG Key ID: 9EEACF1DA75C5627
  1. 10
      solidity/contracts/Indexed.sol
  2. 3
      solidity/contracts/Mailbox.sol
  3. 69
      solidity/contracts/PausableReentrancyGuard.sol
  4. 3
      solidity/contracts/hooks/MerkleTreeHook.sol
  5. 3
      solidity/contracts/igps/InterchainGasPaymaster.sol
  6. 60
      solidity/test/PausableReentrancyGuard.t.sol
  7. 7
      solidity/test/igps/InterchainGasPaymaster.t.sol

@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
contract Indexed {
uint256 public immutable deployedBlock;
constructor() {
deployedBlock = block.number;
}
}

@ -3,6 +3,7 @@ pragma solidity >=0.8.0;
// ============ Internal Imports ============
import {Versioned} from "./upgrade/Versioned.sol";
import {Indexed} from "./Indexed.sol";
import {Message} from "./libs/Message.sol";
import {TypeCasts} from "./libs/TypeCasts.sol";
import {IInterchainSecurityModule, ISpecifiesInterchainSecurityModule} from "./interfaces/IInterchainSecurityModule.sol";
@ -14,7 +15,7 @@ import {IMailbox} from "./interfaces/IMailbox.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract Mailbox is IMailbox, Versioned, Ownable {
contract Mailbox is IMailbox, Indexed, Versioned, Ownable {
// ============ Libraries ============
using Message for bytes;

@ -1,69 +0,0 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
// adapted from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
abstract contract PausableReentrancyGuardUpgradeable is Initializable {
uint256 private constant _ENTERED = 0;
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _PAUSED = 2;
uint256 private _status;
/**
* @dev MUST be called for `nonReentrant` to not always revert
*/
function __PausableReentrancyGuard_init() internal onlyInitializing {
_status = _NOT_ENTERED;
}
function _isPaused() internal view returns (bool) {
return _status == _PAUSED;
}
function _pause() internal notPaused {
_status = _PAUSED;
}
function _unpause() internal {
require(_isPaused(), "!paused");
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from being entered when paused.
*/
modifier notPaused() {
require(!_isPaused(), "paused");
_;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrantAndNotPaused() {
// status must have been initialized
require(_status == _NOT_ENTERED, "reentrant call (or paused)");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}

@ -4,9 +4,10 @@ pragma solidity >=0.8.0;
import {MerkleLib, TREE_DEPTH} from "../libs/Merkle.sol";
import {Message} from "../libs/Message.sol";
import {MailboxClient} from "../client/MailboxClient.sol";
import {Indexed} from "../Indexed.sol";
import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol";
contract MerkleTreeHook is IPostDispatchHook, MailboxClient {
contract MerkleTreeHook is IPostDispatchHook, MailboxClient, Indexed {
using Message for bytes;
using MerkleLib for MerkleLib.Tree;

@ -19,6 +19,8 @@ import {IGPMetadata} from "../libs/hooks/IGPMetadata.sol";
import {IGasOracle} from "../interfaces/IGasOracle.sol";
import {IInterchainGasPaymaster} from "../interfaces/IInterchainGasPaymaster.sol";
import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol";
import {Indexed} from "../Indexed.sol";
// ============ External Imports ============
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
@ -33,6 +35,7 @@ contract InterchainGasPaymaster is
IInterchainGasPaymaster,
IPostDispatchHook,
IGasOracle,
Indexed,
OwnableUpgradeable
{
using Address for address payable;

@ -1,60 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import {PausableReentrancyGuardUpgradeable} from "../contracts/PausableReentrancyGuard.sol";
contract MockPausableReentrancyGuard is PausableReentrancyGuardUpgradeable {
constructor() initializer {
__PausableReentrancyGuard_init();
}
function pause() external {
_pause();
}
function unpause() external {
_unpause();
}
function isPaused() external view returns (bool) {
return _isPaused();
}
function f1() public nonReentrantAndNotPaused {}
function f2() external nonReentrantAndNotPaused {
f1();
}
function f3() external notPaused {}
}
contract PausableReentrancyGuardTest is Test {
MockPausableReentrancyGuard mprg;
function setUp() public {
mprg = new MockPausableReentrancyGuard();
}
function testPause() public {
mprg.f3();
mprg.pause();
vm.expectRevert("paused");
mprg.f3();
mprg.unpause();
mprg.f3();
}
function testNonreentrant() public {
mprg.f1();
vm.expectRevert("reentrant call (or paused)");
mprg.f2();
}
function testNonreentrantNotPaused() public {
mprg.pause();
vm.expectRevert("reentrant call (or paused)");
mprg.f1();
}
}

@ -30,6 +30,8 @@ contract InterchainGasPaymasterTest is Test {
address constant testRefundAddress = address(0xc0ffee);
bytes testEncodedMessage;
uint256 blockNumber;
event GasPayment(
bytes32 indexed messageId,
uint256 gasAmount,
@ -41,6 +43,7 @@ contract InterchainGasPaymasterTest is Test {
event BeneficiarySet(address beneficiary);
function setUp() public {
blockNumber = block.number;
igp = new InterchainGasPaymaster();
igp.initialize(address(this), beneficiary);
oracle = new StorageGasOracle();
@ -55,6 +58,10 @@ contract InterchainGasPaymasterTest is Test {
assertEq(igp.beneficiary(), beneficiary);
}
function testConstructorSetsDeployedBlock() public {
assertEq(igp.deployedBlock(), blockNumber);
}
// ============ initialize ============
function testInitializeRevertsIfCalledTwice() public {

Loading…
Cancel
Save