Drizzle is a collection of front-end libraries that make wirting dapp front-ends easier and more predicable. The core of Drizzle is based on Redux Store, so you can access to the spectacular development tools around Redux. We take care of synchronizing your contract data, transaction data and more. Things stay fast because you declare what to keep in sync.

  • Fully reactive contract data, including state, events and transactions

  • Declarative, so you’re not wasting valuable cycles on unneeded data.

  • Maintainer access to underlying functionaliy. Web3 and your contract’s methods are still there, untouched.

Installation

1
yarn add drizzle

If use React you can use drizzle-react and (optionally) its companion drizzle-react-components

Drizzle uses web3 1.0 and web sockets, be sure your development environment can support these.

  1. Import the provider
1
import { Drizzle, generateStore } from 'drizzle'
  1. Create an options object and pass in the desired contract artifacts for Drizzle to instantiate. Other options are available, just keep going on.
1
2
3
4
5
6
7
8
9
10
11
12
// import contract
import SimpleStorage from './../build/contracts/SimpleStorage.json'
import TutorialToken from './../build/contracts/TutorialToken.json'

const options = {
contracts: [
SimpleStorage
]
}

const drizzleStore = generateStore(this.props.options)
const drizzle = new Drizzle(this.props.options, drizzleStore)

Contract Interaction

Drizzle provides helpful methods on top of the default web3 Contract methods to keep you calls and transactions in sync with the store.

cacheCall()

Gets contract data. Calling the cacheCall() function on a contract will execute the desired call and return a corresponding key so the data can be retrieved from the store.

When a new block is received, Drizzle will refresh the store automatically if any transactions in the block touched our contract.

Note: We have to check that Drizzle is initialized before fetching data. A simple if statement such as below is fine for display a few pieces of data, but a better approach for larger dapps is to use a loading component. Drizzle built one in drizzle-react-component as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Assuming we're observing the store for changes
var state = drizzle.store.getState()

// If Drizzle is initialized (and therefore web3, accounts, and contracts ), continue
if (state.drizzleStatus.initialized) {
// Declare this call to be cached and synchornized. We'll receive the store key for recall
const dataKey = drizzle.contracts.SimpleStorage.methods.storedData.cacheCall()

// Use the dataKey to display data from the store
return state.contracts.SimpleStorage.methods.storedData[dataKey].value
}

// If Drizzle isn't initialized, display some loading indication
return 'loading'

The Contract instance has all of its standard web3 properties and methods. For example, you could still call as normal if you don’t want something in the store:

1
drizzle.contracts.SimpleStorage.methods.storedData().call() // different from methods.storedData.cacheCall()

cacheSend()

Sends a contract transaction. Calling the cacheSend() function on a contract will send the desired transaction and return a correnponding hash so the status can be retrieved from the store. The last argument can optionally be an options object with the typical from, gas, gasPrice keys. Drizzle will update the transaction’s state in the store(pending, success, error) and store the transaction receipt.

Note: We have to check that Drizzle is initialized before fetching data. A simple if statement such as below is fine for display a few pieces of data, but a better approach for larger dapps is to use a loading component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Assuming we're observing the store of changes
var state = drizzle.store.getState()

// if Drizzle is initialized ( and therefore web3, accounts, and contracts ), continue
if (state.drizzleStatus.initialized) {
// Declare this transaction to be observed. We'll receive the stackId of reference.
const stackId = drizzle.contracts.SimpleStorage.methods.set.cacacheSend(2, {from: '0x3f...'})

// Use the dataKey to display the transaction status
if (state.transactionStack[stackId]) {
const txHash = state.trasnactionStack[stackId]

return state.transactions[txHash].status
}
}

// If Drizzle isn't initialized, display some loading indication.
return 'loading'

The contract instance has all of its standard web3 properties and methods.

1
drizzle.contracts.SimpleStorage.methods.set(2).send({from: '0x3f...'})

Options

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
contracts,
events: {
contractsName: [
eventName
]
},
web3: {
fallback: {
type
url
}
}
}
  • Contracts: Array, Required, an array of contract artifacts files

  • Events: Object, an object consisting of contract names each containing an array of strings of the event names we’d like to listen for and sync with the store

  • Web3: Object, options regarding web3 instantiation

  • Fallback: Object, an object consisting of the type and url of a fallback web3 provider. This is used if no injected provider, such as MetaMask or Mist, is detect.

    • type: string, the type of web3 fallback, currently ws is the only possibility

    • url: string, the full websocket url. For example, ws://127.0.0.1:8546

How data stays fresh

  1. Once initialized, Drizzle instantiates web3 and our desired contracts, then observes the chain by subscribing to new block headers

  1. Drizzle keeps track of contract calls so it knows what to synchronize

  1. When a new block header comes in, Drizzle checks that the block isn’t pending, then goes through the transactions looking to see if any of them touched our contracts

  1. If they did, we replay the calls already in the store to refresh any potentially altered data. If they didn’t we continue with the store data.