class TransactionSmartContractPermissioningController implements TransactionPermissioningProvider {

  @Override
  public boolean isPermitted(final Transaction transaction) {
    final org.hyperledger.besu.ethereum.core.Hash transactionHash = transaction.getHash();
    final Address sender = transaction.getSender();

    LOG.trace("Account permissioning - Smart Contract : Checking transaction {}", transactionHash);

    this.checkCounter.inc();
    final Bytes payload = createPayload(transaction);
    final CallParameter callParams =
        new CallParameter(null, contractAddress, -1, null, null, payload);

    final Optional<Boolean> contractExists =
        transactionSimulator.doesAddressExistAtHead(contractAddress);

    if (contractExists.isPresent() && !contractExists.get()) {
      this.checkCounterPermitted.inc();
      LOG.warn(
          "Account permissioning smart contract not found at address {} in current head block. Any transaction will be allowed.",
          contractAddress);
      return true;
    }

    final Optional<TransactionSimulatorResult> result =
        transactionSimulator.processAtHead(callParams);

    if (result.isPresent()) {
      switch (result.get().getResult().getStatus()) {
        case INVALID:
          throw new IllegalStateException(
              "Transaction permissioning transaction found to be Invalid");
        case FAILED:
          throw new IllegalStateException(
              "Transaction permissioning transaction failed when processing");
        default:
          break;
      }
    }

    if (result.map(r -> checkTransactionResult(r.getOutput())).orElse(false)) {
      this.checkCounterPermitted.inc();
      LOG.trace(
          "Account permissioning - Smart Contract: Permitted transaction {} from {}",
          transactionHash,
          sender);
      return true;
    } else {
      this.checkCounterUnpermitted.inc();
      LOG.trace(
          "Account permissioning - Smart Contract: Rejected transaction {} from {}",
          transactionHash,
          sender);
      return false;
    }
  }

  public  TransactionSmartContractPermissioningController(
      final Address contractAddress,
      final TransactionSimulator transactionSimulator,
      final MetricsSystem metricsSystem);

}