The EIP777 can be a bit confusing, specially because it’s a long read and introduces a lot of things.
My understanding of the EIP is that it basically tries to fix problems that EIP20 has while remaining backwards compatible with it - to name some of these problems: the approve-transfer mechanism , that essentially requires two transactions to send tokens on behalf of another address, and sending tokens to contracts that cannot receive them thus locking them forever.
To solve the first problem (approve-transfer) it introduces a new concept that they call operators.
An operator is, in essence, an address that has the right to move tokens on behalf of another address. As such every address is, by default, an operator for itself (i.e I can move my own tokens by default) and this right cannot be revoked.
To allow this, it introduces the functionality to give,
authorizeOperator(), and revoke,
revokeOperator(), operator rights and also introduces the
operatorSend() function that allows an operator to send tokens on behalf of another address.
To solve the second problem (sending tokens to contracts that cannot receive them) it introduces the concept of hooks. These hooks are basically functions that get called when tokens are sent, burned or minted and that are used to notify sender and receiver about the operation that is going to take place - this not only solves this problem but it also allows far more complex operations with the tokens, because contracts can get notified about these token movements and react accordingly.
The hook that notifies the sender is called
tokensToSend() and the hook that notifies the receiver is
Now, to your particular question.
tokensReceived() hook allows contracts to receive ERC777-compliant tokens and react accordingly, to do so they MUST register themselves as
ERC777Recipient implementers by calling the
setInterfaceImplementer() function on a ERC1820 Registry (notice that I said a but there is actually only one registry per network according to the EIP). Notice, that if you try to send tokens to a contract that does not implement the interface, the transaction will fail.
You can read more about the EIP rationale.
EIP1820 introduces the concept of a registry contract which allows contracts to register themselves as interface implementers, for example - I can have my contract register itself as an implementer of the ERC777Recipient interface allowing other contracts to query the registry before trying to interact with me - this allows for more complex operations and can also, potentially, prevent errors.
The EIP also allows addresses to register other addresses as interface implementers on their behalf which allows externally owned accounts to perform more complex operations by having a contract implement - for example - the hooks on their behalf, and not only that, but you can make your old and non-upgradable contract be compatible with another interface by just registering another contract that implements that interface on your behalf.
Notice that EIP777 depends on EIP1820, but the registry contract is completely generic and it would allow you to register other interfaces too.
See EIP1820 ratione.
Hope that clarifies some of your concerns - it’s quite a long EIP and kinda tricky because it has a lot of moving pieces.
Out of curiosity:
Why do you think this particular standard suits your particular use-case best ? I’m not saying it doesn’t, I’m just curious about what you are looking for in terms of functionality.