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.