Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protobuf codegen from ABI events #137

Open
jaimehgb opened this issue Apr 13, 2023 · 0 comments
Open

Protobuf codegen from ABI events #137

jaimehgb opened this issue Apr 13, 2023 · 0 comments
Labels
enhancement New feature or request

Comments

@jaimehgb
Copy link
Collaborator

Summary

We already have some codegen in place, but it goes one way: protobuf -> rust; abi -> rust

If you want to pass ABI events among substream modules, you need a protobuf definition for them. The way we've been doing it so far is by manually creating the protobuf message for the events we want to pass around. This works just fine if you only need to work with a handful events, but as soon as you want to start tracking everything it gets out of hand.

We should be able to generate protobuf messages for each ABI event types, and all the converting code pb<>abi.

Proposal

  1. Generate one protobuf message for each event in the ABIs. It is possible for multiple ABIs to have the same event names, but with potentially different fields. So each message should have prepended the ABI name:

    • message ATokenBurn, message StableDebtTokenBurn, message VariableDebtTokenBurn
  2. At the same time, it is possible for multiple contracts to implement the exact same events (think ERC20 standard). In this case we don't need to prepend the ABI name, but we need a way to tell if a given ABI is from an interface or from a custom contract. We could determine this from the way they are organized in the project:

    • abis/
        commmon/
          erc20.json
          erc721.json
        LiquidityPool.json
        Factory.json
      

NOTE: It could even be smart enough to detect which events in the contract ABIs are already in the common ABIs, so we don't need to generate them every time.

  1. It should also generate all the rust abi to rust pb types and back
  2. The ABI events only contain the fields included in the event, but it is common to also need additional metadata with them (block num, block hash, transaction hash, log index, etc). We could optionally enrich our pb events including all those fields . For example:
    • Event Transfer { from: Vec<u8>, to: Vec<u8>, amount: BigInt } (this is the rust type generated from the ABI)
    • We generate the proto:
      • message Transfer {
          EventMeta meta = 1;
          bytes from = 2;
          bytes to = 3;
          BigInt amount = 4;
        }
        
        message EventMeta {
          bytes address = 1;
          uint32 log_transaction_index = 2;
          uint32 log_block_index = 3;
          int64 timestamp = 4;
          bytes block_hash = 5;
          bytes block_number = 6;
          bytes transaction_hash = 7;
        }
        
    • We can then codegen the implementation of some trait like:
      • pub trait EnrichableEvent {
          fn enrich(&mut self, block: &pb::eth::v2::Block, tx: &pb::eth::v2::TransactionTrace, log: &pb::eth::v2::Log)
        }
  3. You might also want to pass around event types without necessarily knowing which event is beforehand. So, for each ABI, we should also generate a oneof message with all the events from that ABI:
    • message LiquidityPoolEvent {
        oneof event {
          Swap swap = 1;
          Deposit deposit = 1;
          Withdraw withdraw = 2;
          ...
        }
      }
      
      message ERC20Event {
        oneof event {
          Transfer transfer = 1;
          Approval approval = 2;
          ...
        }
      }
  4. Related to the previous point, you might also want to decode a log into an event, only knowing that it will be one of many but without knowing exactly which.
    • fn decode_LiquidityPool_log(log: pb::eth::v2::Log) -> Option<LiquidityPoolEvent> {
        if liquidity_pool::Swap::match_log(log) {
          return Some(abi_name::Swap::decode(log));
        }
        if liquidity_pool::Deposit::match_log(log) {
          return Some(abi_name::Deposit::decode(log));
        }
        if liquidity_pool::Withdraw::match_log(log) {
          return Some(abi_name::Withdraw::decode(log));
        }
        // ...
        None
      }
@jaimehgb jaimehgb added the enhancement New feature or request label Apr 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant