Building a Gnosis Safe Vue.js App

Vincent de Almeida
BlockRocket
Published in
5 min readDec 18, 2020

Gnosis safe is a brilliant multi-sig wallet allowing individuals and teams to secure their assets on Ethereum. As of 1st September 2020, there are over 1bn USD in digital assets secured by Gnosis. We use and recommend Gnosis Safe as it’s a solid offering and meets all the levels of security we expect from a well built product.

Gnosis Safe Challenges

There are many great features and advantages to using a Gnosis safe. However, there are also challenges. The main challenge being that you can’t interact with your favourite dApps like KnownOrigin in the same way you would with MetaMask. This is down to a different flow for the transactions which may include having to wait for the approval of many safe owners before a transaction can be executed on chain.

Gnosis safe does have a transaction builder that enables a technical individual with knowledge on how ABIs work, parameters etc. to create a transaction.

So if we connect the ABI, the contract address….

Enter Gnosis Safe Apps…

A Gnosis Safe App is a dApp that’s built in a bespoke way to be compatible with any Gnosis Safe. Once this dApp has been added / imported within the Gnosis Safe UI, any owner in the safe can transact as they would normally expect in their favourite dApp like KnownOrigin.

Happy days 🚀

Building a Gnosis Safe App in Vue.js

So what’s the recipe for building a Gnosis Safe app in Vue.js? Well, as we’ve recently built an app for a client, we can walk you through what we did!

Ingredients

  • 1x Vue.js vanilla app (Ours is really barebones, Vue 2.x, no Vuex store, hash routing etc.)
  • 1x manifest.json file
  • 1x vue.config.js file
  • 1x @gnosis.pm/safe-apps-sdk npm dependency installed

Instructions

First thing to do, is create a Vue.js app with the following command

vue create gnosis-safe-app

Once created, cd in the directory and install the following dependency:

yarn add @gnosis.pm/safe-apps-sdk

Now, let’s add the 2 files mentioned in the ingredients.

manifest.json needs to go in your public/ directory. What’s the purpose of this file you ask? Apart from being a requirement for a Gnosis safe app, it gives your app a name, description and an icon that will all be displayed in your list of saved apps. Here’s what a file looks like:

{
"name": "CreateVestingSchedule",
"description": "Set up vesting schedules",
"iconPath": "favicon.ico",
"providedBy": { "name": "Blockrocket.tech", "url": "https://blockrocket.tech" }
}

As you can see from our manifest file, our app will allow our client to set up vesting schedules for their token.

One final thing, you’ll need a vue.config.js file with the following:

module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*'
}
}
}

As the gnosis safe UI has to go cross domain (even when deving localling), you need to configure your CORs policy as appropriate. In this case, for our local development, we’re allowing any domain. Without this, the Gnosis safe won’t even be able to resolve your manifest.json file and without that, you won’t be able to add or view the app so this bit is quite crucial. Additionally, when we ended up deploying our app on Firebase, we had to configure the CORs policy at the firebase level to allow the two sites to communicate.

With that house keeping out of the way, we were able to build our app. We kept things simple, sticking to a single component app that was no more than 174 lines long — short and sweet if you like. First thing we did was import the SDK at the top of our scriptblock

import initSdk from '@gnosis.pm/safe-apps-sdk';

Then, when mounted() :

this.appsSdk = initSdk();

// Register callbacks
const onSafeInfo = (safeInfo) => {
this.safeInfo = safeInfo;

this.initContracts();
};

const onTransactionConfirmation = ({ requestId, safeTxHash }) => {
console.log(requestId, safeTxHash);
};

const onTransactionRejection = ({ requestId }) => {
console.log(requestId);
};

this.appsSdk.addListeners({
onSafeInfo,
onTransactionConfirmation,
onTransactionRejection,
});

This initialises the SDK and registers 3 important listeners. When we have a callback into onSafeInfo() we know are connected to a valid safe. safeInfo contains information such as the wallet address which we store. We then go onto initialising our contracts with Web3.

Once we dressed up the UI, we ended up with something looking like this:

Create Vesting Schedule Gnosis Safe App

When we hit create, the following pop up appears:

But what’s happening under the hood? How do we create a TX using the Gnosis SDK?

const txs = [];

// approval
let approvalTx = {
to: tokenContractAddress,
value: 0,
data: this.tokenContract.methods.approve(
vestingContractAddress,
ethers.utils.parseEther(this.form.amount)
).encodeABI(),
};

txs.push(approvalTx);

// create vesting schedule
let createVestingScheduleTx = {
to: vestingContractAddress,
value: 0,
data: this.vestingContract.methods.createVestingSchedule(
this.form.beneficiary,
ethers.utils.parseEther(this.form.amount),
Math.floor(this.form.start / 1000),
this.form.durationInDays,
this.form.cliffInDays,
).encodeABI(),
};

txs.push(createVestingScheduleTx);

// Send to Safe-multisig
this.appsSdk.sendTransactions(txs);

And that’s it 🚀 It just works!

Conclusion

As buidlers, creating a Gnosis safe app has been a pleasant experience. The SDK works well and has good documentation. Gnosis try to do a good job in encouraging Gnosis safe apps to follow a scheme by providing out the box components you can import. However, these components are for React-based apps but it would be good if these were ported to native Vue.js components.

Want us to build a Gnosis safe app, a suite of smart contracts or anything else on your wishlist? Get in touch!

Website — www.blockrocket.tech

Email — hello@blockrocket.tech

Twitter — @blockrockettech

--

--