šŸ—³ Personal Token Voting

Building a signature based voting system for your holders!

Austin Thomas Griffith
8 min readMay 22, 2020

šŸ’”Introduction

ā€œā€˜Talent Is Equally Distributed, But Opportunity Is Notā€™ ā€” this is true. As a founder, most investors are in Silicon Valley. Some write checks to students. Shouldnā€™t we give every deserving person a chance? Wouldnā€™t you buy a stake in young Elon Musk? Whether Income Sharing Agreement (ISA) or ā€˜freelancer timeā€™ to offer work, you can sell some of your future self.

Personal tokens let people fulfill their potential by getting financial and professional support. I believe it reflects Ethereumā€™s inclusiveness, as any person bringing value can rise up in our community. I felt supported myself, and creating my token $ALEX was a logical step. It was technically easy to leverage my supporters: I raised $20,000 in 5 days with zero friction.

However, one side of personal tokens is lacking infrastructure: community governance, or ā€˜guidanceā€™ when advising an individual. Overall Iā€™m fascinated by the future of this space, even beyond entrepreneurs: music artists, athletes, influencersā€¦ā€

šŸ¤” How It Works

So you have a personal token (ERC20) deployed and you want your holders to be able to vote on a proposal. In this demo we will assume that it is okay to do most things off-chain and we will lean back on handy web2 technologies.

However, we will use the power of signed messages and let any user ā€œvoteā€ by signing their preference and sending it to us. Then, at a certain, predetermined time, we can cryptographically validate votes with the signature and weight the vote by the amount of tokens the user holds.

šŸƒā€ā™‚ļø SpeedRun

šŸ‘©ā€šŸ’» Prerequisites

You will need NodeJS>=10 (tested on 10.19.0), Yarn, and Git installed.

Read more about this dev stack: šŸ›  Programming Decentralized Money

šŸ™‡ā€ā™€ļø Getting Started

Letā€™s start with the emoji-vote-dev branch of šŸ— scaffold-eth :

git clone https://github.com/austintgriffith/scaffold-eth.gitcd scaffold-ethgit checkout emoji-vote-devyarn installyarn start

ā˜¢ļø Warning, you may see node-gyp errors, ignore those and try yarn start !

This will bring up a sample emoji voting app that you can fork and change:

First, a user will log in with some sort of web3 wallet or use a burner:

Then, they can click an option to sign their vote with their web3 account:

You can edit what the frontend, in particular the voting options, in the folder packages/react-app/src in the file Vote.js :

You can also edit the page header/title in components/Header.js .

šŸ“” Zapier

These votes are being sent to a Zapier web hook that you can edit here too.

This is handy because then we donā€™t need to run a backend server.

Sign in to https://zapier.com/ and use the big [ + ] button in the top left to ā€œCreate a Zapā€.

(Here is my prebuilt Zap if that will save you some button clicks.)

Select ā€œWebhooks by Zapierā€ then set the Zap to ā€œCatch Hookā€:

Continue and a Webhook will be created for you, copy it:

Edit Vote.js in packages/react-app/src and change the get to your hook:

Hit save and your app should reload.

Make a vote so we can send some test data to your new hook:

After you have voted, continue on in Zapier to ā€œTest Triggerā€:

If weā€™ve done everything right, you will see data from your test vote:

Nice! Letā€™s take a second to celebrate with some emojis: šŸ¾ šŸ„‚ šŸŽ‰ šŸ„³

Now letā€™s continue to the ā€œDo this ā€¦ā€ part and tell Zapier to add a row to a Google Sheet when new data hits our hook.

You will need to create a Google Sheet so it shows up in the next step.

If the Zap finds your sheet you will get a message that we need to add some headers:

ā€œFreezeā€ one row using the view menu and then enter these headers:

address vote timestamp signature

You will want to refresh the fields and then wire them together like:

šŸ’”Neat, it uses the fields from our test request to let us fill in where the data will go in the spreadsheet.

āš”ļø Turn your Zap on:

Now, whenever we make a vote in our app, we should see it show up in the google sheet along with a signature:

šŸ” Verification

We can cryptographically prove that a specific key pair has signed a specific vote string. For instance, the string ā€œemojivoteDOG1590077153770ā€ can be signed and this information is tamperproof. If anything changes, the derived address will be different.

šŸ’” This vote string, along with a signature can be used by anyone to derive the voterā€™s address. šŸ“š Learn more about how key pairs can sign and encrypt.

šŸ’¬ Like my homie, Dan Finlay says, ā€œMake sure your signature challenge is very unique to this poll to avoid replay attacks.ā€

Thatā€™s right! See that ā€œemojivoteā€ up there? That needs to be unique for every poll or you will get votes from one that can work in another one. Maybe put the question of the poll in the vote string?

šŸ›  Try this eth.build to manually verify signatures at first. We can copy and paste values from our spreadsheet into the build to see if the address field is right and also how many of our tokens the voter has:

šŸ˜Ž Rad, now we have signed votes showing up in a familiar interface like google sheets. We could probably verify and count the votes from here, but letā€™s try to šŸ¤– automate a little moreā€¦

āš™ļø Validate Script

There is a simple index.js script in packages/emojivote-validator that will attempt to read, validate, and count totals for votes. You can edit this script and add your sheetā€™s ID:

Then we need to allow access to our script.

Follow this link and click the ā€œEnable the Google Sheets APIā€ button:

Tell it you want a ā€œDesktop Appā€ and click ā€œCreateā€.

Now ā€œDownload Client Configurationā€:

Put this file here: packages/emojivote-validator/credentials.json .

Now we can run our validation script. In the root project directory, letā€™s run this command which should fire up our script:

yarn run validate

(If you are in packages/emojivote-validator you can run node index too.)

When it runs, it will find that we donā€™t have Google auth yet:

Copy and paste that link into a browser to get an auth token. If you are logged in with the right Google account, authorizing the app will take you to a modal where you can copy and paste a code. Paste this code back in the terminal.

Once your script has access, you can run yarn run validate at any time:

šŸ’”This script is checking that voters hold a balance of DAI, but you can change this to your personal token by changing ERC20_TOKEN_ADDRESS in the code.

This will create a file: packages/react-app/src/validVotes.json that is injected into our frontend and has all the vote totals only for valid signatures that hold the ERC20_TOKEN_ADDRESS token specified in the code.

šŸ§® Counting and Displaying Votes

Letā€™s move back to our frontend and look at the App.js file in the folder packages/react-app/src . Toward the bottom you will find two components TimeReport and VoteReport that are hidden:

Remove the display:none and hit save for your app to šŸ”„ hot reload:

You can use the TimeReport section to display to your holders when you will trigger the vote count.

You can use the VoteReport section to display the current valid votes and see who is winning.

Try making a new vote with an account that also owns DAI (or the ERC20) to see an end-to-end voting demo:

You can vote in the frontend with a web3 account, it shows up in your spreadsheet, you validate it with a script, and then the valid vote count is displayed in the frontend.

šŸš¢ Ship it!

Now we want to publish this to our holders. First, build your app:

yarn run build

šŸ’”This creates a ā€˜static siteā€™ in the build directory of packages/react-app .

You can deploy this code to any kind of site host, but weā€™ll use Surge.sh :

npm install --global surgeyarn run surge

You might have to log in first with an email and password. Then it will have your project directory already set to your build directory. You just need to specify a *******.surge.sh domain to publish to:

Then if we visit our .sh domain we should see the app:

šŸ§ Conclusion

Now, your holders should be able to vote on a live site using MetaMask, and you should see the votes show up in your Google Sheet. Then, you can run your validate script to count all the votes. Finally, you can build and deploy the results:

āœļø You can show and hide the different components before you deploy to Surge to control what your holders see.

šŸ—³ This is a rough/quick way to get a vote from your personal token holders without having to do a bunch of on-chain transactions.

šŸ” Thanks to public key cryptography we can verify the votes off-chain!

--

--