4.4 KiB
The main goal of creating a transformer is to fetch specific log events from Ethereum, convert/decode them into usable data and then persist them to VulcanizeDB. For Maker there are two main types of log events that we're tracking: custom events that are defined in the contract solidity code, and LogNote events which utilize the DSNote library. The transformer process for each of these different log types is the same, except for the converting process, as denoted below.
Creating a Transformer for custom events (i.e. FlopKick)
To illustrate how to create a custom log event transformer we'll use the Kick event defined in flop.sol as an example.
-
Get an example FlopKick log event either from mainnet (if the contract has already been deployed), from the Kovan testnet, or by deploying the contract to a local chain and emitting the event manually. We will use the example log event to test drive converting the log to a FlopKick database model.
-
Fetch the appropriate logs from the chain.
- Most transformers use
shared.LogFetcher - Price Feeds
- Convert the raw log into a database model.
-
For Custom Events, such as FlopKick
- Create a converter to convert the raw log into a Go structure.
- We've been using go-ethereum's abigen tool to get the contract's ABI, and a Go struct that represents the event log. We will unpack the raw logs into this struct.
- To use abigen:
abigen --sol flip.sol --pkg flip --out {/path/to/output_file}- sol: this is the path to the solidity contract
- pkg: a package name for the generated Go code
- out: the file path for the generated Go code (optional)
- the output for
flop.solwill include the FlopperAbi and the FlopperKick struct:
type FlopperKick struct { Id *big.Int Lot *big.Int Bid *big.Int Gal common.Address End *big.Int Raw types.Log } - To use abigen:
- Using go-ethereum's
contract.UnpackLogmethod we can unpack the raw log into the FlopperKick struct (which we're referring to as theentity).- See the
ToEntitymethod inpkg/transformers/flop_kick/converter. - The unpack method will not add the
RaworTransactionIndexvalues to the entity struct - both of these values are accessible from the entity.
- See the
- Then convert the entity into a database model. See the
ToModelmethod inpkg/transformers/flop_kick/converter.
-
For LogNote Events, such as tend.
- Since LogNote events are a generic structure, they depend on the
method signature of the method that is calling them. For example,
when the
tendmethod is called on the flip.sol contract, the method signature looks like this:tend(uint id, uint lot, uint bid)- the LogNote event will take the first
- Since LogNote events are a generic structure, they depend on the
method signature of the method that is calling them. For example,
when the
- Persist the log record to VulcanizeDB.
- Each event log has it's own table in the database, as well as it's
own column in the
checked_headerstable.- The
checked_headerstable alllows us to keep track of which headers have been queried for a given log type.
- The
- To create a new migration file:
migrate create -ext sql -dir ./db/migrations/ create_flop_kick- See
db/migrations/1536942529_create_flop_kick.up.sql. - The specific log event tables are all created in the
makerschema. - There is a one-many association between
headersand the log event tables. This is so that if a header is removed due to a reorg, the associated log event records are also removed.
- See
- We have been following a repository pattern to interact with the
database for each table, see the
Createmethod inpkg/transformers/flop_kick/repository.go.
- Get all MissingHeaders. //TODO//
- The repository is also responsible for querying for all header records that have not yet been.
-
MarkHeaderChecked//TODO//
-
Wire each component up in the transformer.
- Each transformer's
Executemethod iterates through all of the MissingHeaders - Currently each transformer's
Executemethod is responsible for fetching the missing headers, meaning the headers that haven't yet been checked for a given log type