district0x / re-frame-web3-fx

⚠️ This code now resides at d0x monorepo

Home Page:https://github.com/district0x/d0x-libs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

re-frame-web3-fx

Build Status

re-frame Effectful Handlers to work with Ethereum blockchain Web3 API, using cljs-web3

Installation

Add Clojars Project into your project.clj Include [district0x.re-frame.web3-fx] in your CLJS file

(ns my.app
  (:require [district0x.re-frame.web3-fx]))

Breaking changes 0.2.3 -> 1.0.0

This library was completely rewritten on version upgrade 0.2.3 -> 1.0.0. API was greatly changed (simplified). Reasons for breakage were also unerlying changes in Ethereum (fork to Byzantium) and preparations for web3 1.0.0. I deeply appologize, but this was absolutely necessary.

API Overview

Usage

Following effect handlers are available:

:web3/call

Use it to call any function from cljs-web3 or any smart contract function. Calling cljs-web3 function:

(reg-event-fx
  ::load-accounts
  (fn [{:keys [:db]} []]
    {:web3/call {:web3 (:web3 db)
                 :fns [{:fn cljs-web3.eth/accounts
                        :args []
                        :on-success [::accounts-loaded]
                        :on-error [::error]}]}}))

Calling constant smart-contract function. In this case getting total supply of a ERC20 Token:

(reg-event-fx
  ::get-token-total-supply
  (fn [{:keys [:db]}]
    {:web3/call {:web3 (:web3 db)
                 :fns [{:instance (:token-contract-instance db)
                        :fn :total-supply
                        :on-success [::token-total-supply-result]
                        :on-error [::error]}]}}))

Calling state changing smart-contract function, aka sending a transaction to the network. In this case calling mint function of MintableToken. Notice there's no on-success, on-error. Given callbacks are executed at following situations:

  • :on-tx-hash When tx is successfully sent to the network. Receives tx-hash in parameters.
  • :on-tx-hash-error When tx wasn't send to the network. Usually user rejected to sign.
  • :on-tx-success When tx was processed without error. Receives receipt in parameters.
  • :on-tx-error When there was an error during processing a transaction. Receives receipt in parameters.
  • :on-tx-receipt General callback when tx was processed. Either with error or not. Receives receipt in parameters. (You don't need to use all of them, only ones you need)

All of these callbacks have their respective multi-event callbacks i.e.:

  • :on-tx-hash-n
  • :on-tx-hash-error-n
  • :on-tx-success-n
  • :on-tx-error-n
  • :on-tx-receipt-n
(reg-event-fx
  ::mint-token
  (fn [{:keys [:db]} [_ {:keys [:to :amount :from]}]]
    {:web3/call {:web3 (:web3 db)
                 :fns [{:instance (:token-contract-instance db)
                        :fn :mint
                        :args [to amount]
                        :tx-opts {:from from
                                  :gas 4500000}
                        :on-tx-hash-n [[::tx-send-success] [::extra]]
                        :on-tx-hash-error [::tx-send-failed]
                        :on-tx-success [::token-minted]
                        :on-tx-error [::tx-failed]
                        :on-tx-receipt [::tx-receipt-loaded]}]}}))

:web3/get-balances

Gets balance of Ether or ERC20 token. Optionally you can pass :watch? true, so the callback will be fired everytime the balance changes. Getting and watching balance or Ether:

(reg-event-fx
  ::load-ether-balances
  (fn [{:keys [:db]} [_ addresses]]
    {:web3/get-balances {:web3 (:web3 db)
                         :addresses (for [address addresses]
                                      {:address address
                                       :watch? true
                                       :on-success [::ether-balance-loaded address]
                                       :on-error [::error]})}}))

Getting and watching balance of a ERC20 Token. Notice you need to pass :instance of a ERC20 contract

(reg-event-fx
  ::load-token-balances
  (fn [{:keys [:db]} [_ addresses]]
    {:web3/get-balances {:web3 (:web3 db)
                         :addresses (for [address addresses]
                                      {:address address
                                       :instance (:token-contract-instance db)
                                       :watch? true
                                       :on-success [::token-balance-loaded address]
                                       :on-error [::error]})}}))

:web3/watch-events

Listens to smart-contract events. Callback receives event :args as first param and complete event data as a second. In this example we watch Mint event of MintableToken

(reg-event-fx
  ::watch-mint
  (fn [{:keys [:db]} [_ {:keys [:to]}]]
    {:web3/watch-events {:events [{:id :mint-watcher
                                   :event :Mint
                                   :instance (:token-contract-instance db)
                                   :block-filter-opts {:from-block 0}
                                   :event-filter-opts {:to to}
                                   :on-success [::token-mint-event]
                                   :on-error [::error]}]}}))

:web3/watch-transactions

Sets up listener until transaction receipt is available. Callbacks are fired same way as in :web3/call for state-changing contract functions.

(reg-event-fx
  ::watch-transaction
  interceptors
  (fn [{:keys [:db]} [tx-hash]]
    {:web3/watch-transactions {:web3 (:web3 db)
                               :transactions [{:id :my-watcher
                                               :tx-hash tx-hash
                                               :on-tx-success [::tx-success]
                                               :on-tx-error [::error]
                                               :on-tx-receipt [::tx-receipt]}]}}))

:web3/watch-blocks

Sets up listener with callback fired on each new Ethereum block.

(reg-event-fx
    ::watch-blocks
    (fn [{:keys [:db]}]
      {:web3/watch-blocks {:id :my-watcher
                           :web3 (:web3 db)
                           :on-success [::new-block]
                           :on-error [::error]}}))

:web3/stop-watching-balances

Stops listeners previously set up with :web3/get-balances

(reg-event-fx
    ::stop-watching-balances
    (fn [{:keys [:db]} [_ addresses]]
      {:web3/stop-watching-balances {:addresses (for [address addresses]
                                        {:address address
                                         :instance (:token-contract-instance db)})}}))

:web3/stop-watching

In any effect handler above, where you could provide :id, you can use this effect handler to stop that listener.

(reg-event-fx
    ::stop-watching
    (fn [{:keys [:db]}]
      {:web3/stop-watching {:ids [:my-watcher]}}))

:web3/stop-watching-all

Stops all listeners set up by all effect handlers.

(reg-event-fx
    ::stop-watching
    (fn [{:keys [:db]}]
      {:web3/stop-watching-all true}))

Running tests

  1. On development machine
  1. On CI (or headless env)
  • npx shadow-cljs compile test-ci
  • CHROME_BIN=`which chromium-browser` npx karma start --single-run`
    

About

⚠️ This code now resides at d0x monorepo

https://github.com/district0x/d0x-libs

License:Eclipse Public License 1.0


Languages

Language:Clojure 81.0%Language:Solidity 17.6%Language:JavaScript 0.9%Language:Shell 0.5%