ZK HACK III - Build a ZKDAO with UniRep Protocol

10 Dec 2022 · 55:44

A ZK HACK III workshop recording from Anna Rose's Zero Knowledge podcast, part of a four-week virtual event pairing technical workshops with a bug-hunting puzzle competition. The session walks through building a ZKDAO, a DAO with anonymous membership and voting, using the UniRep Protocol's create-unirep-app starter kit and its zero-knowledge system for reputation. It covers applications such as anonymous voting and proof-of-assets schemes built with zero-knowledge proofs, with support from sponsors including RISC Zero, Aleo, Aztec, and the Ethereum Foundation.

Topics

Transcript

foreign so thank you all for being here um thank you to zkr for inviting us to present unwrap at this session um right so what am I going to do in this session I'm going to talk a little bit about what Universal reputation is it has like a protocol then I'm going to talk about create UNIF app which is a command line application that we have for building unit rapid testers and then I'll actually try to go from that command line application to a ZK Dao which is a dial where all the participants are Anonymous and um

and they can sort of vote on proposals and spend funds and allow new users to join right so my name is chance I work at the ethereum foundation on the privacy and scaling team and I work on the universal reputation protocol full-time um yeah so let's just jump right into it so I didn't want to prepare slides for this because I just want to do a really short overview so I'm going to use this as my sort of janky slide presentation um so what is universal reputation uh it's a protocol and you can think of it as an identity system where public Keys change over time and this is how we get to anonymity in the protocol so the idea is that we have these units of time that

we call epochs that testers can choose on their own and every Epoch you get new keys that you can use to identify yourself and that's how we get to anonymity it's also an attestation system uh this means that a testers are able to give positive and negative reputation to users that exist within their system uh and you might be asking like what is an attester and a tester is a smart contract that has registered with the unit the unit of smart contract and is now able to make attestations to users so you can think of in a tester to reputation system like an erc20 contract is to a token the tester defines the reputation system defines the rules by which reputation is given who can join

who can participate everything like that and so what is reputation so we Define this as just two integers um one for positive one for negative this allows us to represent uh net negative reputation values uh in like circuits and in contracts without having to deal with actual negative numbers um there are also some other things you can do this with like uh messing with the binary but I'll talk about that a bit later and we also have this graffiti field which is uh just like a bytes 32 and you can use this to set like the value of a hash or or the root of a tree and sort of extend the proof system using this this field so the key parts of the system users are

Anonymous and attestations are non-confidential so you don't know who's participating uh you don't know who's doing what but you can see everything that's happening in the system so you have transparency and anonymity uh yeah and as we go feel free to like post questions or in the chat and whatnot and I'll I see that we lost a chance so give let's give him a little bit of time to come back Anna I don't know oh there we are there we go again okay chance if you could I don't know what happened I tried to tab

okay okay q and Q a tab like you said so don't put them in chats put them in the Q a uh tab next to the chat okay okay cool we're back so yeah just um post questions as we go and I'll try to answer them as we go right so that's like the quick overview of unirp you have like Anonymous users and you're able to track these reputation uh these reputation values that are associated with the user without uh anyone being able to see the actual value that the user holds all right so recently we released this thing called create unwrap app and it's kind of like create react app we named it uh

similarly and the idea is this will bootstrap and a tester and a relay and a front-end application it will boost up all that into a single repo and then you can sort of use it and build in a tester and so I'll quickly just go through how it works in like my temporary directory just create the unwrap app and then it gives you some prompts so we'll just name this like test app and ask where you want to put it by default it's in the current directory and then it'll ask you for package manager and initialize the project and set it up and then once that's done we have some instructions here that are just a few steps that will get you to running this test application and the test application is a sort of

front end that lets you uh just sort of do things with the attest or I'll show it in just a moment when this finishes okay so I'm literally following these instructions over here so let's start this node and we'll use this in a bit as well for other stuff so it comes with this like a a boilerplate contract I need one more okay and we'll start the front end and

we'll start the relay right so you can see the server is interacting with this and we'll pull up the front end so yeah we just released this so it's pretty Bare Bones still uh basically you join the tester and then you'll get a more complete user interface so lets you actually do stuff right so you you get to select this dashboard of what's Happening um you have information about the epoch by default it's 100 seconds so you can get like quick feedback your total reputation your approvable reputation uh and since the options just sort of play with the

tester uh yeah that's create you know about so in this talk I'm going to try to go from just this to a ZK Dao um but I'm going to cheat a little bit because building the front end for an application like this is kind of lame so uh before this talk I went ahead and built a front end and I built the contracts as well and then I sort of erased the contracts and erase the relay logic and just left the front end so we'll take a front end and try to uh try to like build the contracts and relay to go with it and I'm planning to treat this kind of like a programming live stream basically

and if you want to follow along I will post the link oh I can just copy it actually this is the link to the code base that I'm going to be working on you can take a look at it the start branch is the one that I sort of emptied out and then the main branch has like everything built that uh that works so let's take a look at this front end see what it looks like I need to start the relay first I need to deploy first okay so let's talk about what we want to actually build here so

I was thinking about how we can make a ZK dial um when I was trying to think how can we make it like very fair and robust and that sort of led me to um those are way harder to build than I sort of expected so I made a lot of compromises in building this so that we can get this sort of simple example that I can build in an hour and explain an hour and sort of and get anonymity out of it this is the user interface we're going to get to um right so basically we have this dial that has two types of proposals the first type of proposal is a user joining a user proposes that they join the Dow uh and then all the existing users get to vote

on whether or not that user gets to join and the second type of proposal is a spend proposal this is just spending ether that is controlled by the Dow uh yeah and so users that are members of the Dow are able to uh deposit funds into the Dow and then they receive positive reputation equal to the uh number of the amount of funds that they deposited so users can effectively prove how much money they've put into the Dow um yeah that's pretty much it so some technical details so we have these epochs in Europe and we're just going to make it so that whenever a proposal is made it gets voted on in the epoch that it is proposed in and then

the results are done when that Epoch ends and so there's sort of a lot of downsides to that because you could for example like propose or you have to pay attention to when you propose a proposal because if you propose like at the end of an Epoch then no one has an opportunity to vote on it but again this is a simple example we're going to just do uh one Epoch and that's it so all right I'm gonna try to build this so let's take a look at the code base that we're going to start from so this is this is the contract that you get out of create unwrap up um so first let's actually look at the structure of this repo so you get a mono repo with three components you have the

contracts you have the relay which sends transactions and then you have the front end which interacts with the user and so one of the goals we have with unirp is making it so that you don't need to interact with the blockchain directly in order to use these applications so you don't need a wallet in order to use this application you don't need metamask uh you don't need funds uh if you want to deposit funds to the Dow then you do need a wallet but that's the only case um and so the way this works is the relay receives ZK proofs from the front end and then sort of packages those proofs into transactions which are given to the smart contract to actually execute um and then we verify the ZK proof on chain and we verify like data with the

ZK proof so that the relay can't modify what the user actually wants to do so yeah this is the a tester that we start with out of creating rep app so you see we have this Constructor where we just sort of assign the unit variable this is an address and then we do a tester sign up which is how an a tester registers with unit and we tell it what Epoch link we want I think it's set to 100 seconds for this demo uh and then we set the operator to the deployer address um right so in order for a user to sign up they need to provide a sign up proof uh which is generated on the front end and then we call this function in the in our contract which will verify the proof

and do some sort of stuff with the trees that we don't really need to worry about so this is an example function from create your app and we don't need it because um all it does is like give reputation for no reason so we'll take it out uh yeah so let's go ahead and get started trying to build the CK down um so what do we need we need proposals we need one that will spend ether from the treasury and we need one for new users uh we want people to be able to vote on proposals and we wanted to find like a quorum so so the rules for a proposal passing is a

quorum of users need to participate and the majority of the voters need to be in favor of the proposal so you know Quorum which will just be like number of members divided by two and in favor okay cool so let's get started with this so we have two different proposal types let's go ahead and create an enumeration for proposal type and then create a struct for proposal and we'll make the first one sign up and the next one spend

right so now we have this proposal structure however we want to build this we'll make like an index that is a event and okay spend either so for spends we're going to have so the way that I did this is I made a single proposal that that can handle it like both types so it has like variables that are unused for one type or unused for another type so we'll have like uh the address of a recipient a unit which is the amount of funds being spent um okay and then for sign up we're going to have a semaphore public key okay what else do we need we need votes

so we use un 128s for votes for this against right so now we have this problem of we want a quorum for proposals uh and this is the first sort of hiccup we run into so from the uniroc contract we can get the number of members in a tester but the problem is that if we look at the Quorum at like some point in time it can change over the course of an Epoch because users might sign up in the epoch so the solution I came to was just like stick the Quorum on the proposal when it's created um and then if like more users sign up

the Quorum doesn't change um again this isn't like I'm going to say don't don't use the CK dial in production this is more of just an example so we'll just say the Quorum is whatever uh the number of users is whenever uh the proposal is created and then we'll store the epoch that the proposal was created and then we want like descriptions for the proposal but we definitely don't want to store like the full string so we'll put like a description hash on here uh I don't know if the syntax is right but okay right so let's think through how users are going to sign up so we propose sign ups so a user wants

to sign up and they say okay here's a proposal I'm I want to join please vote on it but when we have zero users uh it's kind of hard to say like how should we initialize the system and so the logic that I came to was just like uh if there are zero users in the tester then we just let the operator sign up so let's take a look at the documentation so this is something I'm really excited about we've been working hard on making this documentation like pretty robust it doesn't look great because my screen resolution is very small but hopefully you can see uh there are like lots of functions documented so we have this function a test remember account which will get the number of members in the tester semaphore group

that's what we want so if you interrupt that a test your member count uh and here's some tricky stuff we have to do we accept the arguments as unit 160s so we need to cast all the way to unit 1 Place 60 from like this so that's a little bit ugly but it is what it is so if we have zero members into the group we're going to require message dot sender equals operator otherwise we're going to require whatever we're going to require right so now we need this Logic for letting people sign up so we'll go ahead and make like a mapping that is uh proved semaphore

for some of our pup keys we'll make this a U.S into a Boolean right so now we'll require keys and so now we need to access some information about this sign up proof so what does the sign up proof look like let's go back to these six Docs let's do sound proof right here so we have first we have these outputs identity commitment stage relief thing accessory ID Epoch so we're going to look for identity equipment this will be public key zero or public signal zero and we're just going to require that

because this must we'll set this to True whenever a proposal is executed okay we'll go ahead and leave this I think that changed this something else actually like this okay cool so we have user sign up logic uh let's go ahead and make a proposal some proposal logic so we need two different functions for this let's write this spend one first and we'll take some arguments here right so we need the address of the recipients we

need the un's amount and then what else do we need a description hash okay so this is another flaw in this approach um well it's not necessarily a flaw but the only way that this can safely be executed is if the user calls this function themselves but as you'll see we're going to actually use the relay to call this on behalf of the user so if you provide these arguments to the relay and allow the relay to construct the transaction they can like modify these however they want so just something to bear in mind with the relay architecture okay so we're proposing a spend

um let's go ahead and grab the current Epoch because we need that so you're going to see a lot of like this casting here which is uh just the way it is and then we're going to need an index for this so we need to Define an index somewhere so the way I did it is just a proposal index that is uh increasing over time let me goes public is that where you put the public I think so and we'll just do proposal index Plus that

cool so let's create a proposal object um right uh what do we need for this we need an index recipient amount simple key okay foreign okay index we'll set this to zero we can safely set this to zero because this is effectively a public key so no one's going to know the private key for a zero public key we'll start out with zero votes and then here's where we get to this

weird Quorum logic so we'll grab like the number of a tester or a number of members in the group and we'll divide that by two but immediately we're going to run into a weird problem here so say that we have uh one user in the group we divide it by two let's do we get zero so if we have three users in the group we get two if we just divide by two uh this is not what we want a quorum would actually be two in a group of three because we want to have at least like a majority so what we can do is take like the number of members in the group and add one and then divide it by 2 and we get the result we want so if we have three

then we have two four we have two five we have three seven we have four that's what we want so take this and we'll add one and divide that by two and we'll use that as a quorum and if the number of members changes uh too bad and set the epoch and the description okay so we have like a little bit of a contract here um now how do we get to the point that we can sort of track this off chain so let's take a look at the relay we have this thing called a synchronizer this is what we use in unirp to build off-chain State and at a high level it

just listens for new blocks and then listens for new events and then process the process the events by ingesting them into a local database uh and so we allow this synchronizers to be subclassed and then you can Define the sort of complicated structure that we're going to fix in the future and it will automatically process event listen for and process events on your behalf so we have the cks out uh we want to have an event for when a proposal is created so that we can store it in the database and serve it to the front end so we'll make an event new proposal and we'll make the arguments like uh event index we'll index it and it'll be index

and then we'll put the full proposal data in it as well that's the thing right so we make this and then we emit new proposal uh index proposal cool so now we even did an event but we definitely need this proposal to be like in memory or or in contract storage somewhere so we'll make another mapping and we'll make it U.N students proposal and this will just be proposals by index so here we'll set x x equals proposal

lowercase okay um all right I believe that's all we need for that cool so let's go to the synchronizer and once you have this sort of weird structure you can just add events in The Proposal and then it'll automatically look for a function that is like prefix with the word handle so it'll be like handle new proposal and then you get a bunch of different uh variables on here you get like the event itself you get a database reference and you get decoded data I mean it is async

um right so we need to improve the documentation on the synchronizer but I'll briefly talk about this this database is the reference to a database transaction object so this function is going to be called in the context of a database transaction which means anything you do here is atomic like if you throw an error from here then all the changes that you've made in this function will get rolled back so you can't like leave the database broken you can like close tabs you can do whatever and it's uh safe yeah the the way that we do this is like super opinionated um right so we need the index equals decoded data dot index and this is just like the data as if it were decoded using the interface from

the contract and we're going to parse it into are we going to enter that gstream so this is like a weird thing about decoding data from an event is you get like a big number and if you want to work with it in like a database or sort in a database you need to serialize it somehow and so the native beginner into string is like a the way that we've been doing it it's not a great approach because uh it's very like space inefficient but it's it's very um semantically clear so in this application we have the schema as you can see we have this built-in thing we have like a

transaction manager that will sort of um handle knots management for a wallet and so we're going to extend the schema I'm going to copy and paste this in because I feel like this is going to take much longer than I expected um right so we have like a proposal object which has all these fields that we defined uh in the contract and we also have like this executed variable which is like if it exists and if it's a value one then the proposal has been executed otherwise it hasn't been executed and then we have like a description object or a description variable which is stored here separately so with this in mind let's go ahead and write the logic for handling this event so we'll decode the proposal out of this

and then we'll do gb.create uh right and so you might be wondering like what database are we using here uh and the answer is we have this sort of database wrapper called Anon DB which gives a generic interface for like multiple database backends and the reason we do this is because we want to be able to reuse this sort of complicated logic in both the front end and the back end so when we run the front end application it's doing everything that the back end is doing um in so far it's like it's loading the events from the Internet contract and then building a database of uh state tree leaves and Epoch tree leaves and

attestations and stuff like that because the system is private you can't just ask for like a specific merkel-proof path from uh from like a relay or something because then you reveal like what leads you control so you need to have uh your own database locally and what does it look like you have just like this very simple like find many find one create uh count stuff like that and then the where Clause can have like uh strings integers it can be like an inoperator like one of many uh or and stuff like that just arguments it there and that's what we use internally so we want to create this let's take a look at

oh the screen's too small let me look at this again so we're going to set the index to index just do this so another note um we store most big integers as strings and we serialize them as decimal it just turns into a mess if you have like different encodings um and again like storing big numbers as strings is super inefficient because uh destroying them as like binary representations is like much smaller it's the smallest you can possibly make it and that's something that we're going to add in the next version of anal NTB but for now we use strings so we need the type which is proposal dot oh this needs to be an underscore

actually oh I didn't even store it here cool so you've been underscore type and here we're going to set this is a spin proposal okay okay proposal.underscore type I'm actually going to reference the stuff I already wrote to make sure that I encode these things correctly I'm going to actually copy paste the

rest because this is a little bit tedious that's why I wrote the front end in advance is writing front end stuff is super tedious so basically we just extract these values from The Proposal set the votes to Zero by default and then stick it in the database okay so this is like a decent dropping point or one thing we one more thing we should do is add a route for creating a proposal so the way that this system works is each one of these files is going to get imported and it'll get imported

automatically it lists the contents of routes and then Imports the file and calls the default function with these variables and then you can do whatever you want and so we just do like one file per route and sort of do whatever we need to do in it is where we're here we're gonna make this a proposal post and you don't need a proof to make a proposal you just sort of make your proposal so let's extract some values from body let's do um

what else do we need description that was you for now type oh so now we need to go from description to description hash so we'll go ahead and import the hash function from your app slash utils so this is the Poseidon hash function which we use in all of our proofs because it's very ZK efficient we'll do description hash the downside is you have to sort of serialize this stuff really specifically foreign

X and we'll do like 0x this so the problem is you need to provide like a number to this hash function so we need to convert the string into a number and to do that we'll serialize it to like a buffer and then serialize it to hex string and then put Xerox in front of it and then any hex string can be interpreted as a number and we get a hash value out of that cool so we add that we don't care about the current Epoch okay so now we get to the point of making a function call to the smart contract so we need to force this logic because

we have two different types of spends so if type equals zero I believe that is sign up yeah so that's sign up otherwise we're doing a spend operation so we're going to take this logic and put it up here so as you can see what we're doing we're taking the the contract itself um we're grabbing the ABI from it and then we're making a contract instance using ethers and then we're sort of encoding the data into into call data and giving it to the transaction manager

and queuing it to be sent uh and this is to avoid so the problem is whenever you use like ethereum wallets if you want to send them in a server or from a server you have to deal with the knots value so if you try to send many transactions in parallel you'll get like duplicate nonsense so the transaction manager basically creates a Serial queue and then sends the transactions one at a time so we can handle ingesting like any number or have any number of users submit data to the relay at one time like in parallel so the function we want to encode is for post spend and the arguments we want to give to it are recipients amounts and description hash cool

so now we have our call data and we will cue the transaction to app address which is uh whatever we deploy to and then we get a hash and we'll just give the hashback to the front end and the front ends will then wait for it so let's take a look at the front ends and see what this looks like a little bit so this is the create spend proposal we have like some rudimentary checks on the inputs and then we may click this fetch we pass these values and we get back some data and then we wait for the transaction to succeed and then we reload The Proposal list and that's it right so let me get rid of this example

proposal and we should be able to deploy and run this thing and see a proposal appear I imagine this won't build on the first go though oh it did okay so whenever you do a contract Supply from the create unit app it'll automatically update the addresses so that you can just run the front end and the relay and everything will be using the new addresses that you just deployed which is kind of a nice kind of a nice thing okay

cool so let's see if we can make a proposal right so first we need to join so oops and that's not the logic right so I initially made it so the message sender had to be the operator I think that we can just make this anyone and we'll just do this if it's not equal to zero then we need to have been approved by a proposal so anyone can join if there's no one already in the system

so where we deploy it'll build it automatically right so one of the goals with this is to make building ZK applications that use blockchain uh easy just to make it easier to build applications that use anonymity um and as you can see it's so pretty like I would say the developer experience is like okay to mediocre right now and it was like very bad like a few months ago and we're trying to get to like trying to get to good and that comes with like documentation uh example projects just improves it's like semantics in a lot of this stuff

um stuff like that so this is just sort of where we're at now so let's restart the relay restart the front end reload this I already have one here cool and we'll go ahead and join cool some sort of problem here with the sign up right the contracts oh I know why because I did so let's go look at sign up function

I believe it's calling just sign up and the function name that we get from create UNIF app is user sign up and I changed it because I wanted to make my life difficult I guess so let's deploy one more time and see what happens so yeah I didn't actually time this presentation I just kind of wanted to see perhaps how far I would get just building this looks like I'm about 15 minutes left so we can probably get to the point of uh publishing The Proposal voting on The Proposal and then executing a proposal which is

I don't know that seems pretty okay all right we'll start to relay again let's try this one more time so go to join getting our proving Keys making a proof okay so let's watch the relay and you can see that it's now sending a transaction which is the sign up transaction this will post the ZK proof to the blockchain and then sort of initialize the user into the group it'll add them to the symbol Core group and it'll add them to the state tree for the current epoch cool so let's test out this super Swanky user interface we'll propose a new spend operation so this has to be a valid address

because I had to check into this stream okay it's 40 characters okay neat you know what happened here oh I know what happened we need to write the load uh proposals path so right we have the path to create a proposal but we don't have a path to actually like list the proposals um and I'll also just copy this one instead

of writing it because uh it's pretty pretty simple right so all we're going to get like we're gonna have this API slash proposals and we're just going to list like all the proposals in the database and include this description object which is a related model and we'll go ahead and run this again and now we should be able to load our proposals great so it did work but we missed the window for the epoch because it's only 100 seconds so let's create a new proposal and we'll do Xerox one two three four time ten

do another 0.1 cool let's create this proposal dispense an ether the contract doesn't have sweet here it is so as you can see we have this proposal the Quorum is one because we have one user in the system right now so 100 of the users need to agree because there's only one user uh and there are no votes and we have these four about four vote against so let's go ahead and try to build the voting logic real quick and see if we can get it done so let's go back to the contracts and start there oops

so we're going to write a vote function and we'll have it accept just like a single value which will be the proposal index oh that's not true so in order for a user to vote we want them to prove that they are a member of the group that they're a member of the attester and that they have transitioned to the current Epoch so we're actually going to accept a zero knowledge proof for this so we'll take an array of integers which is going to be the public signals and then we'll take an array of eight which will be the actual proof data itself and so inside the unit contract we have these cool validation functions that will actually deal with verifying the proof for you

and we're using an epocue proof so the important thing here is the epochy proof has some public signals like the state tree route and the current Epoch and you need to verify those against the values that are on chain otherwise you could make a valid proof that proofs against like some state tree that doesn't exist for example and so this function handles that for you believe this is right public signals proof and this will revert if the proof is invalid or if any of the inputs are invalid we need to do some other stuff um it's actually so we have this structure which is Epoch

key signals if I keep proof signals I think memory so let's actually look here epucky signals and it's decode epochy signals so one thing that we do in these proofs um this is actually something I kind of want to talk about so yeah we have this proof and we have a lot of like kind of small inputs like I know it's like a this Epoch uh this variable that's like should I reveal the not saw you

um and so naively we could put each of these into a public signal and give it to the proof but then we have perhaps four public signals for what could be put into a single signal um and so what we do is we use one signal and we just say like the first eight bits are for the knots the next 64 bits are for the epoch makes 160 bits for the test writing we sort of do that and then in the zero knowledge proof we we parse out the certain bit ranges and convert them into full integers inside of the proof and so by doing this we reduce the number of public signals which reduces the verification complexity which reduces like amount of gas used to verify uh and it also reduces the number of public signals which reduces the

amount of call data that you have to send and so that's what this decode epoxy signals is doing it's taking like this control field and parsing out these four values into named variables so that we can use them so let's just that's one of the optimizations that we applied in like the last couple of weeks I think it's pretty neat so we'll take signals.efoc and we'll require that in order to vote you make a zero knowledge proof using the current Epoch so those you like unit dot a test your current epoch that is nasty cast again and we'll add an error or a message to this error to help debug in case we need to

and we'll also require that the tester ID is equal to us so they don't make a proof for a different contract I think this is going to be a unit okay so we have our proof verified uh now we want to deal with um so so inside of an epochy proof you get like this data field which is right here and the reason you want to have all of this inside of a single proof is because the user is going to make this proof from their browser and then give it to the relay and you don't want the relay to be able to modify any of the signals that are being passed to the

smart contract so you want the proof to specify everything that you're doing so in this vote we need to specify two things we need to specify how we're voting for or against and we need to specify the index that we're voting for so again we can use like this same approach for control Fields or that we use for control Fields we'll do like is the vote for uh the proposal and we'll use the first bit from the data field so what we'll do is signals.data and one so this is like a binary and against the number one and this will output either one or zero uh depending on the first bit of

the data field and so then if this is equal to one so now we have we'll actually make this a pool and then we'll use for the index we'll use like the remaining bits to represent the index so index will just be signals.data shifted to the right by one bit and now we have our index and our four value cool so we want to grab our proposal X index and we'll Fork it like is for

oh it does that okay uh yeah and then we'll emit an event as well and and we'll do a Boolean like is it are they voting forward are they voting against it and at this event okay let's see if that builds so we have this written in there now we

need to add a route that will allow us to make the vote we'll just call this like vote.n.js and again I'm just gonna rip this out of the example for the sake of brevity so right so in this function we're going to take a ZK proof from the request and we have like these utility classes that you can use to sort of like decode the proof and get values out of the public signals and then we'll verify it make sure the proof is valid we'll check that the current Epoch matches the value in the proof and if

all that checks out we'll broadcast it we'll call the vote function and we'll pass the public signals in the proof and that will get passed to this function which will then increment the book value in The Proposal so we have that wired up this may be built didn't build 93. definitely name this wrong you should see the public key signals all right these need to be Memory I guess these could be called Data but

I'm just gonna Mark the memory all right and we'll go ahead and deploy the next version so once this is deployed we should theoretically be able to vote on the proposals that we make so we'll go ahead and make a spend proposal and then try to vote on it and see what happens okay go ahead and refresh it and because we did redeploy we need to

go ahead and join again as the first user cool all right go ahead and make our proposal cool so now we have this proposal here and we have these options to vote for never vote against these are already implemented in the front end um they'll handle like encoding let's actually take a look in order to vote yeah so

here's where we build like this data value where we take like the proposal index and like shift it to the left by one bit and then we add just like a one or a zero depending on whether or not we're voting for or against so we'll go ahead oops not that before this let's see if this works cool so we sent the transaction and we voted for uh but we didn't add the event handler so we admitted this event proposal vote we need to go to app synchronizer add a new events and then add

take this index I'm actually going to rip this as well because I don't want to mess up uh the decoding of this foreign value and then we update the proposal that the proposal record where the index is this and we set either votes for uh to one order against oh we need to actually do addition here but we can

leave like this just for testing so we'll go ahead and restart the relay and we should actually see this update because it's going to reprocess all of the events that have happened right so you have one four vote and we have met the requirement for quote for a quorum so assuming that we have like execution support we would be able to execute this uh yeah so let's go ahead and take a look at the actual ZK dial code that's actually functioning or actually why don't I just check that Branch out and then we can try that foreign that we'll go ahead and start the front

end and start the relay and I'll just sort of skip ahead and show you uh the finished thing and sort of how it works thank you right again if you want to test this check out the main branch I set the start Branch as the default just uh for no reason the main branch has the actual finished code start the relay so the front end back here and so it's pretty much the same logic join create a proposal except in this case you can execute the proposal if it

succeeds so let's take a look at ZK dial contract right you got like deposit logic you have sign up logic you have uh execution logic uh yeah I guess it was a bit optimistic to think that I could write all of that in an hour but uh as we'll try all right so the logic is we create a proposal in an epoch just 60 seconds remaining so we can only vote on it in the current Epoch so we'll go ahead and vote cool we have a quorum and then at the

end of the cpoc it'll move over here and we'll be able to execute it one time so while we're doing this I'm going to actually grab our GitHub or not our GitHub our Discord URL oh this is new this looks neat that's cool and paste it into the chat if you want to join our Discord that's where we communicate about um the projects we communicate like internally but we also have like public channels uh it looks like there's not a lot of activity but I assure you we are responsive on there if you have questions or if you want to build stuff um

yeah it's kind of interesting this is like a pre-release version of version 2 of unit so there's sort of a lot of shortcomings so so like for one thing when we vote we use epoc Keys which means that we're not actually Anonymous like we're Anonymous across epochs but if there were like five proposals in a single Epoch we would be pseudonymous and so the way that we could fix that is by adding support for like semaphore external nullifiers so basically we take the hash or our private key hold that executed so we take the hash of like our private key uh and hash it against like the proposal index that we're voting on and then that becomes our identifier um and so yeah like we built we built

these like toy projects and then sort of find these new use cases and build them into uh like the next versions of unirap so um Yeah we actually have like time budgeted for building small applications like this uh yeah that's just about the end of my presentation [Music]