Using the Vue Drizzle Plugin within a Production Web3 Dapp
FRESH CHAIN-DATA FOR FRONT-ENDS
Drizzle is a collection of front-end libraries that make writing dapp user interfaces easier and more predictable.
Coming from the Truffle guys, Drizzle is mainly an abstraction over the web3.js library built by the ethereum foundation for the purpose of interacting with Smart Contracts on the Ethereum blockchain. Drizzle’s goals are to significantly reduce the barrier to entry by abstracting away a lot of the complexities and time associated with bootstrapping your Web 3 enabled web application.
As a Web 3 focused company, BlockRocket has implemented solutions in many different ethereum focused libraries such as ethers, ethjs, web3js etc. VueJs is our web framework of choice for building web applications for the decentralised web. With the introduction of the Drizzle Vue plugin, we took the opportunity to take it for a test drive in our latest client project — Twisted Sister.
Twisted Sister
The basic idea of the project is to facilitate the auctioning 21 pieces of NFT-based digital art using Ethereum and IPFS.
Our job was to create a web application that can
- Submit bids to an auction running within a Smart Contract on the Ethereum blockchain and,
- See what art was sold at each of the previous rounds.
The main focus of this article will be on the front-end and the usage of Vue Drizzle - we won’t delve into the contracts.
Wiring up Drizzle to our Typescript Vue.js App
In order to wire up the Drizzle vue plugin to the Vue app, we need to install the package first!
npm i @drizzle/vue-plugin
Then within our main.ts file, we connect it to Vue with 3 lines of code:
Notice that we had to use //@ts-ignore on the plugin import. This is because at the time of writing, a typescript module definition file doesn’t exist. Hopefully this gets added soon (something we need to really contribute back to the project).
drizzle-options is the only config file you need for Drizzle to function. For this project, ours was defined as follows:
The main aim of this config file is to specify the contracts you’re interested, any events within those contracts and how often to check the blockchain for new data. You just need to import the truffle json generated when compiling the smart contracts — that’s it!
Something that’s interesting and which you won’t see in a lot of examples is our use of an object to define not only the name of the event within a contract that you’re interested in, but also the starting block from which you care about the events. Instead you could define the file like this:
Where on a per-contract basis the list of events to watch is just an array of strings. However, you will only get events from the current block number (relative to when you started the webapp). This can be problematic when you’re trying to display historical event data that exists since the contract was deployed so watch out for that gotcha!
{
eventName: 'BidAccepted',
eventOptions: { fromBlock: 0 }
}
One thing I will say is that within your event watch definition object (such as the one above), the fromBlock property should really be the block that your contract was deployed at. Setting it to zero in our example was fine as we were running it locally on a Ganache instance.
Anyway, with this up and running, we can now fetch data from the blockchain…
Fetching and rendering contract data
We tried a couple of patterns when fetching blockchain data using Drizzle Vue as detailed in the sub-sections below. However, they may not be the best so we are open to better ways of data management using Drizzle within a Vue.js application.
Event data
Using mapGetters we can access an object given to us by Drizzle and make it a computed property within any component — contractInstances. It allows us to access the events emitted by a given contract amongst other things. During the course of developing the Twisted Sister Dapp, we built up a collection of utility functions that were being repeatedly used across the application. The following is a simplified version of a function that we packaged up into a typescript NPM module:
It’ll return an array of events matching the name specified. We had to introduce the second filter as there was a weird bug within the drizzle framework which was injecting duplicate events as they were coming in. However, the duplicates were not present on refresh.
You could also subscribe to live event changes like this:
this.$drizzleEvents.$on('drizzle/contractEvent', payload => {
// const { contractName, eventName, data } = payload
// Do something with payload data
})
General contract data
This is public contract state and custom functions that fetch data. One of the things you have to understand when using Drizzle is that when the app is first started, Drizzle needs to be initialised meaning it’s not initially available. Secondly, after it’s been initialised, you then have to register what contract data you’re interested in using a store dispatch. After registering watchers on contract data, there will be a small delay in going to the blockchain and getting the data back in your application’s store. If contract data has not yet come back from the blockchain, Drizzle Vue will return the following string in place of that data: loading.
All the above points are important to note as attempts to access and use the drizzle instance or contract data when they’re not ready can cause your web app to grind to a halt, or even implode. So how was this managed?
Well, the created() lifecycle hook is a perfectly good place to register interest in any piece of contract data like so:
This dispatch pattern works well for contract calls which infrequently change. For example, the above watches the contract for the value of minBid and can be displayed throughout the webapp by any interested component. Each component will always get the latest value every 5 seconds. However, it seems like an overkill when you want to fetch contract data on a one-off basis. For example, if we had a search form that was exposed to the user, dispatching a watch on something short lived like a search doesn’t seem to be a great idea. A callback or promise-based approach would be better in those cases which you could do by popping out the web3 instance from Drizzle. However, that doesn’t seem like the best pattern.
As for interacting with the drizzle instance and retrieving the contract data, the best pattern appeared to be to define a computed property. The aim of the computed property is to return a default value until both the drizzle instance is ready and the contract data has arrived. Here’s the minBid computed property from one of our components showing this in action:
This way, the view is able to gracefully render some defaults until the real data kicks in from the contract. etherFromWei is another utility method we wrote which checks that the drizzleInstance is valid, min is valid and not equal to ‘loading’ and then uses web3.js utils to convert the uint256 value from the contract into ether. By default, if Drizzle is not initialised, it will return the DEFAULT_MIN_BID constant. Ideally, this should be part of the Drizzle Vue library.
Submitting Transactions
Of course, as well as fetching contract data, we want to be able to submit data to contracts through transactions.
Calling a contract method was straightforward. The main steps are to get a reference to the contract method that you want to call. Once you have that, you can then call ‘cacheSend’ on this with the required parameters and additionally any value you wish to send. This can be seen in the example below:
When a user hits the button on the front-end, it will prompt their wallet provider which in turn will ask for the transaction to be signed. This is all a seamless process and given our Drizzle instance is configured to poll every 5 seconds, the effect of the transaction will be seen pretty quickly.
However, we did struggle to get access to the pending transaction status of a submitted transaction. There are some Drizzle documents but these are React-focused. Even with some persistence and example React code for pulling the transaction status from the Drizzle state, we couldn’t get this to work and were unsure why. This is a shame, especially considering we couldn’t easily get at the transaction hash that which would have allowed us to at least generate an Etherscan link for the user.
Conclusion
Our conclusion is that the Drizzle Vue plugin seems to do somethings really well and enables the rapid prototyping of web apps that can interact with the Ethereum blockchain. Having said that, Drizzle Vue has a long way to go to achieve maturity so proceed with caution when deciding to use it. In addition to the issues mentioned above, we found that the fallback functionality didn’t work. It also did not gracefully handle the scenario where the user’s provider is on a different network to where a contract is actually deployed (deployed contract addresses being defined in the truffle config). It would also be great to also have a ‘please connect to MetaMask’ banner component or similar helper components that quickly polish a dapp — it’s a recognised pattern throughout many dapps to display those things. Furthermore, it would be great to have multi provider support i.e. portis, Dapper Labs, Wallet Connect etc with a helper login component for selecting the provider. The 3 components that are currently packaged within Drizzle vue are also too basic.
Let us know what you think of the Drizzle Vue plugin and whether you’ve used it or are considering using it.
If you want to speak to us directly about how to leverage this and more Web 3 tools, please reach out to us using the links below.
Website — www.blockrocket.tech
Email — hello@blockrocket.tech
Twitter — @blockrockettech
Check out our community meetup for our up and coming events — Blockchain Manchester
If you enjoyed this post please show it some ❤️ and give it a clap of 50 👏👏👏 — Vincent