How to create a soulbound governance token in 5 minutes (or less!)

Dennison Bertram
Tally
Published in
3 min readJun 2, 2022

--

Soulbound Tokens, or SBTs, are hot right now. Like, really hot.

Described in Puja Ohlhaver, Vitalik Buterin, and Glen Weyl’s recent paper “Decentralized Society: Finding Web3’s Soul”, SBTs are essentially non-transferable NFTs. Because they are non-transferable, SBTs can be associated with one specific person or “soul” and used to represent an individual’s unique on-chain identity. You can imagine soulbound tokens being used to represent all sorts of important permanent information such as voting history or on-chain work credentials. With a collection of soulbound tokens, an on-chain “soul” or identity can represent a definitive, decentralized on-chain repository of information about a specific person.

One promising use case for SBTs is DAO governance. For example, soulbound tokens can be used to implement one-person, one-vote rules, or to enforce on-chain voting requirements for specific proposals.

Let’s build one!

Despite the lofty sounding name, SBTs are down to-earth tech. We already have and know all the code necessary to build them. In this example we will build a non-transferable NFT which can be used with OpenZeppelin Governor to power a DAO.

Step 1

To start, we’ll open the OpenZeppelin Wizard to build the base of our contract.

Since we’re building an NFT, we’ll select “ERC721” as our contract type, “Mintable” so we can create new ones and “Votes” so it’s compatible with DAOs.

Step 2

Now that we have the base, we need to customize our code. To do that, let’s open our code in Remix by clicking, “Open in Remix”. You can also click here to open in Remix.

The code should look like this:

Github: https://gist.github.com/crazyrabbitLTC/d1298c1666c1fb3f05cf2ff11ecd5a07

We already have all the code necessary to launch a DAO Compatible NFT token! (The OpenZeppelin Contracts Wizard is pretty awesome). Now, we just need to make a few changes to make it “soulbound” (i.e. non-transferable).

In the OpenZeppelin ERC721 Contracts API docs, you will find some hooks that we will use to control the transferability of our tokens.

We are already using function _afterTokenTransfer(address from, address to, uint256 tokenId) but we need to add a new function to check before a token is transferred to stop it from happening.

To block token transfers, add the following to your code:

Github: https://gist.github.com/crazyrabbitLTC/00a969fbeb4baf9a266ce74eb9390416

Now, before anyone sends a token, the require statement will check if: true == false

and when it obviously doesn’t it, will block the transfer with the error message Err. token is SOUL BOUND.

Step 3:

Great, except we have a problem. This hook will run on all transfers meaning it will even block minting which is technically a transfer from the zero address to a real address. This isn’t a soulbound token, it’s just broken!

To fix it, we should do a check to see that the sender is the zero address, that way we know this is a mint transaction and not a transfer. Let’s update our code to check for this:

Github: https://gist.github.com/crazyrabbitLTC/4c0fa2bfab0334a36e8575ac0ea5b2ea

Perfect! Now we have a soulbound NFT that can be minted, but not transferred. This is perfect for non-transferable voting systems, or badges that you don’t want participants to sell on the open market. Because we’re using ERC721 with the Votes extension, our new SBT is also ready for use in a DAO with OpenZeppelin Governor.

The final Code:

Enjoy!

For more useful DAO content follow Tally on Twitter, Medium, and YouTube.

--

--