Skip to content
This repository has been archived by the owner on Dec 12, 2022. It is now read-only.

district0x/district-server-web3-events

Repository files navigation

district-server-web3-events

CircleCI

Clojurescript-node.js mount module for a district server, that enables easier setting up and handling web3 smart-contract events. This module provides ordered dispatching across different smart-contract events. Other server modules can simply plug in into dispatching cycle by registering callback(s) for any event, being free from handling troublesome web3 events directly. It also provides ability to cache events into a local file, for later replaying of events from the file. This is especially useful when debugging QA or production and not having locally synced blockchain.

Installation

Latest released version of this library:
Clojars Project

Include [district.server.web3-events] in your CLJS file, where you use mount/start

API Overview

Warning: district0x modules are still in early stages, therefore API can change in a future.

Usage

You can pass following args to web3-events module:

  • :events Collection of smart-contract events the module will start listening to. Pass definition for each event in format [contract-key event-key event-opts block-opts]
  • :from-block You can explicitly configure from which block the past events will be retrieved
  • :block-step Size of block chunk when syncing past events (see replay-past-events-in-order).
  • :crash-on-event-fail? When set to true, will crash the server on a unhandled event exception.
  • :checkpoint-file The file that will be used to store checkpoints information for incremental event processing
  • :backtrack Amount of blocks to look back before checkpointed when starting the module

Let's see example of using this module:

(ns my-district.smart-contracts)

(def smart-contracts
  {:my-contract
   {:name "MyContract"
    :address "0x0000000000000000000000000000000000000000"}})

If you're unfamiliar with smart-contracts definition above, please check district-server-smart-contracts.

Let's take for example simple module, which is supposed to perform some actions on smart-contract events:

(ns my-district.my-module
  (:require
    [mount.core :refer [defstate]]
    [district.server.web3-events :refer [register-callback! unregister-callbacks!]]))

(defn handle-some-event []
  (println "Handling some event"))

(defn handle-some-other-event []
  (println "Handling some other event"))

(defn start []
  (register-callback! :my-contract/some-event handle-some-event ::some-event)
  (register-callback! :my-contract/some-other-event handle-some-other-event ::some-other-event)
  opts)

(defn stop []
  (unregister-callbacks! [::some-event ::some-other-event]))

(defstate my-module
  :start (start)
  :stop (stop))

Now all we need to do is to include our module and configure web3-events:

(ns my-district
  (:require [mount.core :as mount]
            [district.server.smart-contracts]
            [district.server.web3-events]
            [my-district.smart-contracts]
            [my-district.my-module]))


(-> (mount/with-args
      {:web3 {:port 8545}
       :smart-contracts {:contracts-var #'my-district.smart-contracts/smart-contracts
                         :print-gas-usage? true}
       :web3-events {:events {:my-contract/some-event [:my-contract :SomeEvent]
                              :my-contract/some-other-event [:my-contract :SomeOtherEvent]}
                     :from-block 900}})
    (mount/start))

And that's all! Now handlers in my-module will be fired in exact order as they went through the blockchain.

module dependencies

district-server-web3-events gets initial args from config provided by district-server-config/config under the key :smart-contracts. These args are then merged together with ones passed to mount/with-args.

district-server-web3-events relies on getting web3 instance from district-server-web3/web3. That's why, in example, you need to set up :web3 in mount/with-args as well.

district-server-web3-events relies on accessing smart-contract instances via this module. That's why, in example, you need to set up :smart-contracts in mount/with-args as well.

If you wish to use custom modules instead of dependencies above while still using district-server-web3-events, you can easily do so by mount's states swapping.

district.server.web3-events

Namespace contains following functions for working with web3 events:

Registers a callback by the key you've passed into configuration of this module. Callback will receive contract and event as well, so it can be identified backwards. Optionally, you can pass callback-id by which you can unregister callback, if not supplied random will be generated and returned from the function call.

Registers a callback that will be fired once, after all past events were replayed and before listening on latest events starts. No need to unregister this callback, since it's fired only once, it's automatically unregistered.

Unregisters collection of callbacks by their ids.

Development (build, test)

Node.js

  1. Compile the contracts: npx truffle migrate --reset --network ganache
  2. Build: npx shadow-cljs compile test-node
  3. Tests: node out/node-tests.js

Build & release with deps.edn and tools.build

  1. Build: clj -T:build jar
  2. Release: clj -T:build deploy