This ClojureScript library provides a API for interacting with Ethereum nodes.
Latest released version of this library:
Core functions which deal with creating and checking the status of Web3 connections.
This function is the gateway to using the library. Most other functions will take the map it returns as their first argument, unless specified otherwise.
It creates a Web3 instance over a websocket connection. Takes an the url and a map of options as parameters. Returns a the websocket (the provider)
Example:
(ns my-district
(:require [cljs-web3.core :as web3-core]
[web3.impl.web3js :as web3js]))
(def web3 (web3-core/websocket-provider "ws://127.0.0.1:8545" {:client-config {:max-received-frame-size 100000000
:max-received-message-size 100000000}}))
Similar to websocket-provider, but creates a Web3 instance from a URL address.
NOTE some functions, notably subscriptions (see e.g. subscribe-events), will work differently with than http-provider
, which is why it's generally recommended to use the websocket connections for your subscriptions.
Allows for extending the Web3 object with any supported JSON RPC method, which is otherwise not a part of this library. Takes as arguments:
- a map returned by the websocket-provider or http-provider function.
- the module name (a keyword)
- a colection of
method
maps with following keys:name
: Name of the method to addcall
: The RPC method nameparams
: The number of parameters for that call (optional)
Example:
(extend web3
:evm
[{:name "increaseTime"
:call "evm_increaseTime"
:params 1})])
Returns the same web3 map as passed, but now the provider is extended with the increaseTime
method in the evm
module, which you can invoke like this:
(.increaseTime (aget web3 :provider "evm") 1000)
Takes as arguments a map returned by the provider function and returns the URL of the node it is connected to.
(connection-url web3)
;; "ws://127.0.0.1:8545"
Takes as arguments a map returned by the provider function and returns the connection status as a boolean value. This function is synchronous, for an asynchronous method see is-listening?.
Immediately disconnects the provider, returns nil
.
(disconnect web3)
Takes a provider map and a callback function as arguments, callback is executed when the connection is established.
(web3-core/on-connect web3 (fn [event] (prn "just connected")))
Takes a provider map and a callback as arguments, callback is executed when the connection is dropped.
(web3-core/on-disconnect web3 (fn [event] (prn "your web3 socket has lost its connection")))
Similar as on-connect and on-disconnect but executes the callback when connection throws an error.
This namespace contains functions for interacting with the Ethereum blockchain and Ethereum smart contracts.
Asynchronous version of the connected? function, takes the provider map and a callback function. Returns a JS/Promise which returns a boolean.
You can use it to set a periodically executing connection healthcheck:
(js/setInterval (fn []
(is-listening? web3
(fn [_ connected?]
(when-not connected?
(reset-connection)))))
3000)
Takes a provider map, contract abi interface as returned by the solc compiler (in a JSON format). Returns a Contract instance.
(def abi (aget (.readFileSync js/fs MyContract.json) "abi))
(contract-at web3 abi "0x98f93ed24052ceed35741beee1d75287cb297137")
Takes a provider map, transaction hash (a String) and an optional callback function. Returns a JS/Promise which evaluates to the receipt of that transaction.
(get-transaction-receipt web3 "0xd5000d0de00e50d6ac47fe48d11d9dc8258e74fc69b57b5c804e7ddc424af8d0" (fn [tx] (prn "I got the receipt" tx))
Returns the availiable ethereum accounts in the wallet on the node it is connected to.
(accounts web3)
Takes a web3 map and an optional callback as arguments. Returns a JS/Promise which evaluates to the current block number.
(get-block-number web3)
Takes as arguments:
- a web3 map
- a block number or hash
- a boolean parameter specifying whether to include the transactions
- an optional callback
Returns a JS/Promise which evaluates to the representation of the last mined block.
(get-block web3 block-number false)
This function returns the ABI bytecode of a transaction.
It takes as arguments:
- the provider map
- smart contract instance, as returned by the contract-at function
- the kebab-cased keyword with the name of the smart contracts function
- a vector with the arguments of the function
Returns bytecode as a string.
(encode-abi web3 my-contract :set-counter [3])
This function executes a statless (read only) method of a smart contract.
It takes as arguments:
- the provider map
- smart contract instance, as returned by the contract-at function
- the kebab-cased keyword with the name of the smart contracts function to execute
- a vector with the arguments of the function
- map of options:
:from
: the account calling the contract (see accounts)
Returns a JS/Promise which evaluates to the return value of that function.
(web3-eth/contract-call web3
my-contract
:my-plus
[3 4]
{:from (first accounts)})
This function executes a state-altering (payable) method of a smart contract.
It takes as arguments:
- the provider map
- smart contract instance, as returned by the contract-at function
- the kebab-cased keyword with the name of the smart contracts function to execute
- a vector with the arguments of the function
- map of options:
:from
: the account calling the contract (see accounts):gas
: max amount of gas you are willing to spend
Returns a JS/Promise which evaluates to the tx-hash once the transaction is mined.
(<! (web3-eth/contract-send web3
my-contract
:set-counter
[3]
{:from (first accounts)
:gas 4000000}))
Creates a subscription listening to a specific contracts event.
It takes as arguments:
- the provider map
- smart contract instance, as returned by the contract-at function
- the CamelCased keyword with the name of the smart contracts event to listen to
- map of options:
:from-block
: the block number (greater than or equal to) from which to get events on.
- a nodejs-style callback function (
error
is a first parameters andresponse
the second), executed each time the event is seen (optional)
Returns a EventEmitter
object which can be subsequently used with on to react to an even finer-grained control.
(web3-eth/subscribe-events web3
my-contract
:SetCounterEvent
{:from-block block-number}
(fn [error event]
(prn "new event" event})))
This function lets you create subscriptions listening to specific logs of things happening on the blockchain, filtered by a given list of topics.
It takes as arguments:
- the provider map
- map of options:
:from-block
: the block number (greater than or equal to) from which to get events on.:address
: a string or a vector of strings with addresses to listen to:topics
: An vector of values which must each appear in the log entries. Order needs to match the order in the:address
vector.
- a nodejs-style callback function (
error
is a first parameters andresponse
the second), executed each time the log is seen (optional)
(subscribe-logs web3
{:address [address]
:topics [event-signature]
:from-block block-number}
(fn [_ event] (prn event))
Similar to the subscribe-events function, it returns an EventEmitter
which can be augmented using on.
Use this function to decodes an ABI encoded log data and indexed topic data, such as returned by the subscribe-logs subscription.
Arguments:
- the provider map
abi
: a map of interface inputs arraydata
: the abi bytecode of the data field in the log (a string)topics
: a vector of the topics of the log (see subscribe-logs)
This function can be used with the EventEmitter
returned by the subscribe-events and subscribe-logs.
It will add callbacks executed on specific events:
:connected
: fires the callback when the subscription is created, returns the id of that subscription as the first argument of the callback:data
: fired on each incoming log with the log object as argument. If the subscription happens ot be listening to a smart event contract the event passed as th ecallback argument is the same as for the subscribe-events.:changed
: fires when the log is removed from the blockchain:error
: fires when an error in the subscription occurs.
(-> event-emitter
(#(on web3 % :connected (fn [sub-id]
(prn "subscribed to SetCounterEvents. Subscription id :" sub-id))))
(#(on web3 % :data (fn [event]
(prn "new SetCounterEvents :" event))))
(#(on web3 % :error (fn [error]
(prn "Error :" error)))))
Clears a subscription, takes a web3 provider an an event emitter (returned by the subscribe-events or subscribe-logs) as arguments.
(web3-eth/unsubscribe web3 event-emitter)
Clears all created subscription.
Returns all past events for the specified contract.
It takes as arguments:
- the provider map
- smart contract instance, as returned by the contract-at function
- the CamelCased keyword with the name of the smart contracts event to replay
- map of options:
:from-block
: the block number (greater than or equal to) from which to return the events:to-block
: the block number (less than or equal to) up to which the events are returned
- a nodejs-style callback function (
error
is a first parameters andresponse
the second), executed each time the event is seen (optional)
(web3-eth/get-past-events web3
my-contract
:SetCounterEvent
{:from-block 0
:to-block "latest"}
(fn [events]))
A subscribe-logs equivalent of get-past-events.
(web3-eth/get-past-logs web3
{:address [address]
:topics [event-signature]
:from-block 0
:to-block "latest"}
(fn [logs]))
This namespaces provides various utility functions.
Returns a sha3 of the input.
Implementation of Solidity sha3 function. Takes a web3 provider and a variable number of arguments, returns a hash value (a string).
(solidity-sha3 web3 "0x7d10b16dd1f9e0df45976d402879fb496c114936" 6 "abc")
(from-ascii web3 args)
(to-ascii web3 arg)
(number-to-hex web3 number)
(from-wei web3 number <unit>)
(to-wei web3 number <unit>)
(address? web3 address)
NOTE The functions in this namespaces are not a part of the API unless you extend the evm
module with these RPC calls.
They will only to work with a testrpc such as ganache
Increases the blockchain time by the specified number of seconds.
(increase-time! web3 [seconds] callback)
Instantly mines a block.
(mine-block web3 callback)
Snapshot the state of the blockchain at the current block.
(snapshot! web3 callback)
Revert the state of the blockchain to a previous snapshot.
(revert! web3 [snapshot-id] callback)
Functions in this namespace are not part of the API, rather help in turning the JS objects returned by the API funcions to the corresponding Clojure data structures. As such they are independent of the currently used implementation and do not take the web3 provider as their first argument.
From JavaScript Object to Clojure map with kebab-cased keywords, e.g. :
#js {:fromBlock 0, :toBlock "latest"}
;; =>
{:from-block 0 :to-block "latest"}
From Clojure with kebab-cased keywords to JavaScript e.g.
{:from-block 0 :to-block "latest"}
;; =>
#js {:fromBlock 0, :toBlock "latest"}
Given a contract instance returned by the contract-at function and a :CamelCase
key of the event, returns the abi interface of that event, which can be used e.g. with subscribe-logs.
(event-interface my-contract :SetCounterEvent)
Given a returnValues
field (part of the data return by subscriptions, such as subscribe-events) and an event-interface returns a edn (aka Clojure) representation of this events return values.
(return-values->clj return-values event-interface)
lein npm install
npx truffle develop
npx truffle migrate --network ganache
As this library is meant to work both in browsers and on Node.js (server), it must be tested on both as well. Additionally CI runs the tests slightly different way, so that's the 3rd test environment.
- it's still in browser, but CI gets success vs failure depending on the
- browser process exit code so a bit of extra work is needed to get it out from JS (Karma is used for that)
- Build:
npx shadow-cljs compile test-node
- Tests:
node out/node-tests.js
- Build:
npx shadow-cljs watch test-browser
- Tests: http://d0x-vm:6502
- Build:
npx shadow-cljs compile test-ci
- Tests:
CHROME_BIN=`which chromium-browser` npx karma start karma.conf.js --single-run
- Run headless chrome:
chromium-browser --headless --remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 --allowed-origins="*" https://chromium.org
- Open
chrome://inspect/#devices
and configure remote target with IP ADDRESS (hostname doesn't work)
- Build:
clj -T:build jar
- Release:
clj -T:build deploy