ERC777 Contract with ERC20 Tokens received

I will share the code I have it so far.

1. XToken777Recipient Contract

You can see that the code is the same as in this Simple ERC777 token example
I just added revert function into tokenReceived function

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC777/IERC777.sol";
import "@openzeppelin/contracts/introspection/IERC1820Registry.sol";
import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";

contract XToken777Recipient is IERC777Recipient {
    IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
    bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");

    IERC777 private _token;

    event DoneStuff(address operator, address from, address to, uint256 amount, bytes userData, bytes operatorData);

    constructor (address token) {
        _token = IERC777(token);

        _erc1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, address(this));
    }

    function tokensReceived(
        address operator,
        address from,
        address to,
        uint256 amount,
        bytes calldata userData,
        bytes calldata operatorData
    ) external override {
        revert();
        require(msg.sender == address(_token), "XToken777Recipient: Invalid token");

        // do stuff
        emit DoneStuff(operator, from, to, amount, userData, operatorData);
    }
}
2. Truffle migration: 2_deploy.js
const XToken777Recipient = artifacts.require('XToken777Recipient');

require('@openzeppelin/test-helpers/configure')({ provider: web3.currentProvider, environment: 'truffle' });

const { singletons } = require('@openzeppelin/test-helpers');

module.exports = async (deployer, network, accounts) => {
    if (network === 'development') {
        // In a test environment an ERC777 token requires deploying an ERC1820 registry
        await singletons.ERC1820Registry(accounts[0]);
    }

    await deployer.deploy(XToken777Recipient, "0x8D8ab567C57De121C515c85c24f9B3d796c0872A"); // Contract address of XToken Testnet link: https://rinkeby.etherscan.io/token/0x8D8ab567C57De121C515c85c24f9B3d796c0872A
};
3. Truffle config: truffle-config.js
const HDWalletProvider = require('@truffle/hdwallet-provider');

module.exports = {
  networks: {
    development: {
      protocol: 'http',
      host: 'localhost',
      port: 8545,
      gas: 5000000,
      gasPrice: 5e9,
      networkId: '*',
    },
    rinkeby: {
      network_id: '4',
      provider: () => new HDWalletProvider(
          ['<privateKey>'],
          'https://rinkeby.infura.io/v3/<apiKey>'>,
          0,
          1,
      ),
      gasPrice: 10000000000, // 10 gwei
      gas: 6900000,
      from: '<ownerAddress>',
      timeoutBlocks: 500,
    }
  },
  mocha: {
    // timeout: 100000
  },
  compilers: {
    solc: {
      version: '0.8.0',
      docker: false,
      parser: 'solcjs',
      settings: {
        optimizer: {
          enabled: true,
          runs: 50000
        },
        evmVersion: 'istanbul',
      }
    }
  },
  db: {
    enabled: false
  }
};

Now i will explain the whole process step by step:

  1. Created an ERC20 token named: XToken Testnet (XTT)
  2. Created new user address and sent 5000 XTT to it
  3. Ran command: migrate --network rinkeby
2_deploy.js
===========

   Deploying 'XToken777Recipient'
   ------------------------------
   > transaction hash:    0x9c4feebdff10a771a31b5bf32d7db82de2e295c3e7f153e288c5b08044c63e09
   > Blocks: 0            Seconds: 8
   > contract address:    0x96aBa35C73Ff3d86f4d904B26C94CF373B214Cc6
   > block number:        8779769
   > block timestamp:     1623932892
   > account:             0x58C7716959efb3E6495793956F639Efc2a3412Aa
   > balance:             1.99554411
   > gas used:            220137 (0x35be9)
   > gas price:           10 gwei
   > value sent:          0 ETH
   > total cost:          0.00220137 ETH
  1. From XToken User I sent 10 XTT tokens to XToken777Recipient contract

So you can see that the transaction has been confirmed and should be reverted. You can see revert function in XToken777Recipient tokenReceived function.