Generic, EVM compatible blockchain event listener service that actively scrapes FeesCollected
events from LI.FI FeeCollector
contract. For more details see Challenge Specification.
It was a fun challenge!
To run the project:
- Clone repo to local
git clone https://github.com/jamado95/lifi-challenge.git
- Install node modules (node v18.18.2, all packages use latest version)
npm ci
- Build project (optional)
npm run build
- Setup local MONGODB_URL, PORT, POLYGON_PROVIDER_URL and POLYGON_FEE_COLLECTOR_CONTRACT configurations in
.env
file. See working example bellow.
# Remove flag to disable debug logs. Recommend keep enabled for better visibility
DEBUG=true
PORT=3000
MONGODB_URL=mongodb://localhost:27017/test
BLOCKCHAIN=POLYGON
POLYGON_PROVIDER_URL=https://polygon-rpc.com
POLYGON_FEE_COLLECTOR_CONTRACT=0xbD6C7B0d2f68c2b7805d88388319cfB6EcB50eA9
- Run unit tests
⚠️ Ensure you're using a clean/empty dedicated testing database.
npm run test
- Run project with ts-node.
npm run dev
The project has been tested locally and should be working as expected and described in the challenge according to my best interpretation of the specs. Feel welcome to reach out with any questions, or issues while trying to run the project!
The repo contains a generic implementation of an EVM compatible, statefull event listener that can be found at src/ContractEventListener.ts
. The listener and its state manager are designed in such a way as to allow for multiple listener instances to run concurrently, with each instance scrapping data for an unique combination of blockchain network, contract address and event types. The listener implements a basic backoff strategy with limited retry attempts for handling errors related to provider timeouts, too many events errors and oversized block query space errors.
The listener will start to scrape the selected blockchain network (.env:BLOCKCHAIN
) between [latest_block - MAX_BLOCK_DIFF, latest_block] where MAX_BLOCK_DIFF is set to 2000 blocks (see src/ContractEventListener.MAX_BLOCK_DIFF
). The listener can be started and stopped at will, and its expected to resume operations from it left off.
Scrapping happens every src/ContractEventListener.SCRAPE_INTERVAL
milliseconds. Feel free to reduce this interval for testinf purposes (recommended 10seconds);
Alter the EventListenerState.state.lastFetchedBlock
in the database to determine the staring block from which the listener will start scrapping the blockchain for events.
The service implements a paginated endpoint to retrieve scrapped FeesCollected
events. The endpoint's implementation along with its interface can be found at src/router.ts
.
The endpoint can be accessed at http://<host>:<PORT>/events/fees-collected/:integrator?offset=0&limit=10
where integrator
is the checksummed address of the desired integrator, and PORT
is defined at .env
file. The paginated parameters are optional and default to the 10 oldest events stored in the database.
Example endpoint call: http://localhost:3000/events/fees-collected/0x1aC3EF0ECF4E0ed23D62cab448f3169064230624?offset=0&limit=10
- Add unit testing to API endpoint; Extend unit test coverage of listener functionality;
- Enable historical event scrapping in the codebase (the listener has this functionality enalbed and working, but it must be managed by directly updating its state on the database);
- Endpoint interface type and schema validators, caching and authentication;
- Redundant mechanisms to ensure strong data consistency, with focus on avoiding duplicate events in the database;
- Improvements on
src/technical/provider
module including fallback provider and support for multiple concurrent providers; - Handle blockchain reorgs with strong data consistency (ex. discard events from the database that no longer appear in the canonical blockchain path);