EVM hooks router issue notes
===
## Research issue [#1244](https://github.com/evmos/ethermint/issues/1244)
ideas:
register module (evmos) for the hook (defined in ethermint) -> register handler (evmos)
agregar logica -> segun tipo de mensaje/evento/condicion, qué handler se ejecuta -> una func CheckEvent (o algo asi) al Handler y devuelve si se tiene que ejecutar o no --> entonces solo ejecuto los handlers que necesito
este caso es inverso al uso del Router -> en el router, éste se llama desde el modulo que lo registra...
En el caso de el evmHook, muchos modulos se registran en el router del mismo modulo y se llama alli
### Questions
Cual es la funcionalidad deseada??
### Ideas
Dynamically add/remove hooks depending on the tx type, using a middleware
### EVM hooks (PostTxProcessing) logic
#### ERC-20 - mint/burn ERC-20 tokens
* iterates receipt.Logs _question: only way to do it?_
* check for **ERC20EventTransfer**
* check that contract is **registered pair**
* check if tokens are sent to ERC-20 module address
* correspondingly mint or burn coins
* transfer tokens from module to recipient account
_this runs in every tx_
_question: this case will be always a tx to a contract, right?? so we could make the checks (e.g.: if registered) based on the msg data instead of the receipt logs?_
#### Revenue - send fees to withdrawer
* check if tx **to a contract**
* check if contract is **registered** to receive fees
* define withdrawer addr
* calculate the fees for the withdrawer
* send conis from module to the withdrawer
#### Incentives - interaction with incentivezed contract: add gas used
* check if tx **to contract**
* check if contract is **registered** for incentives
* check receiver is EOA
* Add gas used to
* incentivized contract
* participant
#### Claims - claimable amount for user's record evm action is redeemed
* check if sender has claimsRecord
* claim coins for ActionEVM
### Possible implementation
Based on this logic, the router would be something in the terms of:
```
// claims hook runs for all txs
hooks := []hooks{claimsHook}
// register hooks before returning
defer registerEVMHooks(hooks)
// with current logic this is checked 3 times
// check msg.To() is an addr
contract := msg.To()
if contract == nil {
return
}
// check which hook should run
id := k.GetERC20Map(ctx, contract)
// other ERC-20 checks...
if isErc20 {
hooks = append(hooks, erc20Hook)
}
revenue, isRevenue := k.GetRevenue(ctx, *contract)
if isRevenue {
hooks = append(hooks, revenueHook)
}
isIncentive := k.IsIncentiveRegistered(ctx, *contract)
if isIncentive {
hooks = append(hooks, incentivesHook)
}
```
**Idea**
To avoid checking many times if msg is for contract, we need to consolidate the basic checks in one place (e.g. if tx is to a contract).
Ideas:
* define a hook type (in Ethermint) for this use case (tx to contract)
* Another is to dynamically change the registered hooks (in Evmos)
Then do the check one time and run these hooks if fulfill the condition.
__router pattern con__: Using the router pattern will duplicate logic too, cause each handler for each case will have the same check as it is now.
Logic will change in the `hooks.go`
```
// PostTxProcessing delegate the call to underlying hooks
func (mh MultiEvmHooks) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
if msg.To() == nil {
return nil
}
for i := range mh {
if err := mh[i].PostTxProcessing(ctx, msg, receipt); err != nil {
return sdkerrors.Wrapf(err, "EVM hook %T failed", mh[i])
}
}
return nil
}
```
Other option is to add a check in the `state_transition.go` for the new types of hooks, and only run these if it is a tx to contract
Other option is to add a Check fn in the hooks to run before calling the main fn. Example
```
// this check should be added where the hook is called to avoid repetition
if msg.To() != nil {
PostTxToContractProcessing(ctx, msg, receipt)
}
// PostTxToContractProcessing delegate the call to underlying hooks
func (mh MultiEvmHooks) PostTxToContractProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
for i := range mh {
if ok := mh[i].Check(ctx, msg); !ok {
return nil
}
if err := mh[i].PostTxToContractProcessing(ctx, msg, receipt); err != nil {
return sdkerrors.Wrapf(err, "EVM hook %T failed", mh[i])
}
}
return nil
}
```
__Pros of adding the Check__: it is cleaner to understand that the error occurred while processing the tx
__Cons of adding the Check__: does not make much difference with how is implemented now, not sure if it is worth the effort.