diff --git a/contracts/fast/FastInitFacet.sol b/contracts/fast/FastInitFacet.sol
index 001c844b..d30b0b35 100644
--- a/contracts/fast/FastInitFacet.sol
+++ b/contracts/fast/FastInitFacet.sol
@@ -7,6 +7,7 @@ import "../common/lib/LibHasAutomatons.sol";
 import "../common/AHasGovernors.sol";
 import "../common/AHasMembers.sol";
 import "../common/AHasAutomatons.sol";
+import "../interfaces/IERC165.sol"; // Interface detection.
 import "../interfaces/IERC173.sol"; // Ownership.
 import "../interfaces/IDiamondCut.sol"; // Facet management.
 import "../interfaces/IDiamondLoupe.sol"; // Facet introspection.
@@ -21,8 +22,6 @@ import "./lib/LibFastHistory.sol";
 import "./lib/LibFastDistributions.sol";
 import "./lib/LibFastCrowdfunds.sol";
 
-import "@openzeppelin/contracts/interfaces/IERC165.sol";
-
 /**
  * @notice NotAlthough this contract doesn't explicitelly inherit from IERC173, ERC165, IDiamondLoupe etc, all
  * methods are in fact implemented by the underlaying Diamond proxy. It is therefore safe to
diff --git a/contracts/interfaces/IERC165.sol b/contracts/interfaces/IERC165.sol
new file mode 100644
index 00000000..e5885239
--- /dev/null
+++ b/contracts/interfaces/IERC165.sol
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.10;
+
+/// @title ERC165 definition - interface implementation queryability.
+interface IERC165 {
+  /// @notice Queries if a contract implements an interface
+  /// @param interfaceId The interface identifier, as specified in ERC165.
+  /// @notice Interface identification is specified in ERC-165. This method uses less than 30,000 gas.
+  /// @return A `bool` set to `true` if the contract implements `interfaceID` and
+  /// `interfaceID` is not 0xffffffff.
+  function supportsInterface(bytes4 interfaceId) external view returns (bool);
+}
diff --git a/contracts/issuer/IssuerInitFacet.sol b/contracts/issuer/IssuerInitFacet.sol
index 97d7e534..cf374681 100644
--- a/contracts/issuer/IssuerInitFacet.sol
+++ b/contracts/issuer/IssuerInitFacet.sol
@@ -3,6 +3,7 @@ pragma solidity 0.8.10;
 
 import "../common/AHasMembers.sol";
 import "../common/AHasAutomatons.sol";
+import "../interfaces/IERC165.sol"; // Interface detection.
 import "../interfaces/IERC173.sol"; // Ownership.
 import "../interfaces/IDiamondCut.sol"; // Facet management.
 import "../interfaces/IDiamondLoupe.sol"; // Facet introspection.
@@ -13,8 +14,6 @@ import "./lib/AIssuerFacet.sol";
 import "./lib/LibIssuer.sol";
 import "./lib/LibIssuerAccess.sol";
 
-import "@openzeppelin/contracts/interfaces/IERC165.sol";
-
 /**
  * @title The Issuer Smart Contract.
  * @notice The marketplace contract is in charge of keeping track of marketplace members and has logic
diff --git a/contracts/marketplace/MarketplaceInitFacet.sol b/contracts/marketplace/MarketplaceInitFacet.sol
index a752f269..36db5aab 100644
--- a/contracts/marketplace/MarketplaceInitFacet.sol
+++ b/contracts/marketplace/MarketplaceInitFacet.sol
@@ -7,6 +7,7 @@ import "../common/lib/LibHasForwarder.sol";
 import "../common/AHasMembers.sol";
 import "../common/AHasAutomatons.sol";
 import "../common/AHasForwarder.sol";
+import "../interfaces/IERC165.sol"; // Interface detection.
 import "../interfaces/IERC173.sol"; // Ownership.
 import "../interfaces/IDiamondCut.sol"; // Facet management.
 import "../interfaces/IDiamondLoupe.sol"; // Facet introspection.
@@ -17,8 +18,6 @@ import "./lib/LibMarketplace.sol";
 import "./lib/LibMarketplaceAccess.sol";
 import "./lib/LibMarketplaceTokenHolders.sol";
 
-import "@openzeppelin/contracts/interfaces/IERC165.sol";
-
 /// @notice The Marketplace initialization facet.
 contract MarketplaceInitFacet is AMarketplaceFacet {
   /// Initializers.
diff --git a/contracts/paymaster/PaymasterInitFacet.sol b/contracts/paymaster/PaymasterInitFacet.sol
index b67e07d3..ad96d675 100644
--- a/contracts/paymaster/PaymasterInitFacet.sol
+++ b/contracts/paymaster/PaymasterInitFacet.sol
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: MIT
 pragma solidity 0.8.10;
 
+import "../interfaces/IERC165.sol"; // Interface detection.
 import "../interfaces/IERC173.sol"; // Ownership.
 import "../interfaces/IDiamondCut.sol"; // Facet management.
 import "../interfaces/IDiamondLoupe.sol"; // Facet introspection.
@@ -9,8 +10,6 @@ import "../lib/LibDiamond.sol";
 import "./lib/APaymasterFacet.sol";
 import "./lib/LibPaymaster.sol";
 
-import "@openzeppelin/contracts/interfaces/IERC165.sol";
-
 /// @notice The Paymaster initialization facet.
 contract PaymasterInitFacet is APaymasterFacet {
   /// Initializers.
diff --git a/contracts/paymaster/PaymasterTopFacet.sol b/contracts/paymaster/PaymasterTopFacet.sol
index 3d58b62c..ac2f354f 100644
--- a/contracts/paymaster/PaymasterTopFacet.sol
+++ b/contracts/paymaster/PaymasterTopFacet.sol
@@ -4,9 +4,131 @@ pragma solidity 0.8.10;
 import "./lib/LibPaymaster.sol";
 import "./lib/APaymasterFacet.sol";
 
-import "@opengsn/contracts/src/BasePaymaster.sol";
+import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
+
+import "@opengsn/contracts/src/interfaces/IPaymaster.sol";
+import "@opengsn/contracts/src/interfaces/IRelayHub.sol";
+import "@opengsn/contracts/src/forwarder/IForwarder.sol";
+import "@opengsn/contracts/src/utils/GsnEip712Library.sol";
+
+contract PaymasterTopFacet is APaymasterFacet, IPaymaster {
+  using ERC165Checker for address;
+
+  IRelayHub internal relayHub;
+  address private _trustedForwarder;
+
+  /// @inheritdoc IPaymaster
+  function getRelayHub() public view returns (address) {
+    return address(relayHub);
+  }
+
+  //overhead of forwarder verify+signature, plus hub overhead.
+  uint256 public constant FORWARDER_HUB_OVERHEAD = 50000;
+
+  //These parameters are documented in IPaymaster.GasAndDataLimits
+  uint256 public constant PRE_RELAYED_CALL_GAS_LIMIT = 100000;
+  uint256 public constant POST_RELAYED_CALL_GAS_LIMIT = 110000;
+  uint256 public constant PAYMASTER_ACCEPTANCE_BUDGET = PRE_RELAYED_CALL_GAS_LIMIT + FORWARDER_HUB_OVERHEAD;
+  uint256 public constant CALLDATA_SIZE_LIMIT = 10500;
+
+  /// @inheritdoc IERC165
+  function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
+    return interfaceId == type(IPaymaster).interfaceId;
+  }
+
+  /// @inheritdoc IPaymaster
+  function getGasAndDataLimits() public view virtual returns (IPaymaster.GasAndDataLimits memory limits) {
+    return
+      IPaymaster.GasAndDataLimits(
+        PAYMASTER_ACCEPTANCE_BUDGET,
+        PRE_RELAYED_CALL_GAS_LIMIT,
+        POST_RELAYED_CALL_GAS_LIMIT,
+        CALLDATA_SIZE_LIMIT
+      );
+  }
+
+  /**
+   * @notice this method must be called from preRelayedCall to validate that the forwarder
+   * is approved by the paymaster as well as by the recipient contract.
+   */
+  function _verifyForwarder(GsnTypes.RelayRequest calldata relayRequest) internal view virtual {
+    require(getTrustedForwarder() == relayRequest.relayData.forwarder, "Forwarder is not trusted");
+    GsnEip712Library.verifyForwarderTrusted(relayRequest);
+  }
+
+  function _verifyRelayHubOnly() internal view virtual {
+    require(msg.sender == getRelayHub(), "can only be called by RelayHub");
+  }
+
+  function _verifyValue(GsnTypes.RelayRequest calldata relayRequest) internal view virtual {
+    require(relayRequest.request.value == 0, "value transfer not supported");
+  }
+
+  function _verifyPaymasterData(GsnTypes.RelayRequest calldata relayRequest) internal view virtual {
+    require(relayRequest.relayData.paymasterData.length == 0, "should have no paymasterData");
+  }
+
+  function _verifyApprovalData(bytes calldata approvalData) internal view virtual {
+    require(approvalData.length == 0, "should have no approvalData");
+  }
+
+  /**
+   * @notice The owner of the Paymaster can change the instance of the RelayHub this Paymaster works with.
+   * :warning: **Warning** :warning: The deposit on the previous RelayHub must be withdrawn first.
+   */
+  function setRelayHub(IRelayHub hub) public {
+    require(address(hub).supportsInterface(type(IRelayHub).interfaceId), "target is not a valid IRelayHub");
+    relayHub = hub;
+  }
+
+  /**
+   * @notice The owner of the Paymaster can change the instance of the Forwarder this Paymaster works with.
+   * @notice the Recipients must trust this Forwarder as well in order for the configuration to remain functional.
+   */
+  function setTrustedForwarder(address forwarder) public virtual {
+    require(forwarder.supportsInterface(type(IForwarder).interfaceId), "target is not a valid IForwarder");
+    _trustedForwarder = forwarder;
+  }
+
+  function getTrustedForwarder() public view virtual returns (address) {
+    return _trustedForwarder;
+  }
+
+  /**
+   * @notice Any native Ether transferred into the paymaster is transferred as a deposit to the RelayHub.
+   * This way, we don't need to understand the RelayHub API in order to replenish the paymaster.
+   */
+  receive() external payable virtual {
+    require(address(relayHub) != address(0), "relay hub address not set");
+    relayHub.depositFor{value: msg.value}(address(this));
+  }
+
+  /**
+   * @notice Withdraw deposit from the RelayHub.
+   * @param amount The amount to be subtracted from the sender.
+   * @param target The target to which the amount will be transferred.
+   */
+  function withdrawRelayHubDepositTo(uint256 amount, address payable target) public {
+    relayHub.withdraw(target, amount);
+  }
+
+  /// @inheritdoc IPaymaster
+  function preRelayedCall(
+    GsnTypes.RelayRequest calldata relayRequest,
+    bytes calldata signature,
+    bytes calldata approvalData,
+    uint256 maxPossibleGas
+  ) external returns (bytes memory, bool) {
+    _verifyRelayHubOnly();
+    _verifyForwarder(relayRequest);
+    _verifyValue(relayRequest);
+    _verifyPaymasterData(relayRequest);
+    _verifyApprovalData(approvalData);
+    return _preRelayedCall(relayRequest, signature, approvalData, maxPossibleGas);
+  }
+
+  ///// OLD SHIZZLE /////
 
-contract PaymasterTopFacet is APaymasterFacet, BasePaymaster {
   bool public useRejectOnRecipientRevert = false;
 
   // TODO: Do we use the Marketplace at this point to check that the sender is allowed?
@@ -15,7 +137,7 @@ contract PaymasterTopFacet is APaymasterFacet, BasePaymaster {
     bytes calldata signature,
     bytes calldata approvalData,
     uint256 maxPossibleGas
-  ) internal virtual override returns (bytes memory context, bool revertOnRecipientRevert) {
+  ) internal returns (bytes memory context, bool revertOnRecipientRevert) {
     (signature, maxPossibleGas);
     if (approvalData.length == 0) revert ICustomErrors.InvalidApprovalDataLength();
     if (relayRequest.relayData.paymasterData.length == 0) revert ICustomErrors.InvalidPaymasterDataLength();
@@ -23,16 +145,27 @@ contract PaymasterTopFacet is APaymasterFacet, BasePaymaster {
     return ("", useRejectOnRecipientRevert);
   }
 
+  /// @inheritdoc IPaymaster
+  function postRelayedCall(
+    bytes calldata context,
+    bool success,
+    uint256 gasUseWithoutPost,
+    GsnTypes.RelayData calldata relayData
+  ) external {
+    _verifyRelayHubOnly();
+    _postRelayedCall(context, success, gasUseWithoutPost, relayData);
+  }
+
   function _postRelayedCall(
     bytes calldata context,
     bool success,
     uint256 gasUseWithoutPost,
     GsnTypes.RelayData calldata relayData
-  ) internal virtual override {
+  ) internal {
     (context, success, gasUseWithoutPost, relayData);
   }
 
-  function versionPaymaster() external view virtual override returns (string memory) {
+  function versionPaymaster() external view returns (string memory) {
     return "3.0.0-beta.3+opengsn.accepteverything.ipaymaster";
   }
 }
diff --git a/hardhat.config.ts b/hardhat.config.ts
index 8603ade1..b15321f8 100644
--- a/hardhat.config.ts
+++ b/hardhat.config.ts
@@ -52,7 +52,6 @@ const config: HardhatUserConfig = {
         ["Facet$", "RequiresFastContractCaller()"],
       ]),
       include: [
-        "IERC165",
         "IERC173",
         "IDiamondCut",
         "IDiamondLoupe",
@@ -76,7 +75,6 @@ const config: HardhatUserConfig = {
         ["Facet$", "RequiresMarketplaceMembership(address)"],
       ]),
       include: [
-        "IERC165",
         "IERC173",
         "IDiamondCut",
         "IDiamondLoupe",
@@ -115,7 +113,6 @@ const config: HardhatUserConfig = {
         ["Facet$", "InvalidCrowdfundBasisPointFee(uint32)"],
       ]),
       include: [
-        "IERC165",
         "IERC173",
         "IDiamondCut",
         "IDiamondLoupe",
@@ -133,8 +130,7 @@ const config: HardhatUserConfig = {
         ["Facet$", "InvalidPaymasterDataLength()"],
       ]),
       include: [
-        // "IERC165",
-        // "IERC173",
+        "IERC173",
         "IDiamondCut",
         "IDiamondLoupe",
         ...PAYMASTER_FACETS,
diff --git a/tasks/paymaster.ts b/tasks/paymaster.ts
index 16f07d37..63ced915 100644
--- a/tasks/paymaster.ts
+++ b/tasks/paymaster.ts
@@ -86,6 +86,9 @@ const deployPaymaster = async (
       },
       deterministicSalt: deploymentSalt(hre),
       log: true,
+      excludeSelectors: {
+        "PaymasterTopFacet": ["supportsInterface"]
+      }
     });
   }
   // Return a handle to the diamond.