A Look at the Tech That Powers the Latest Version of Kleros...
Last month, after lots of hard work behind the curtains, we released the new and improved version of the Kleros protocol, Athena. A lot of research and innovation has gone into greatly improving the user experience since the last version of Kleros. Before, we only had the Doges on Trial token curated registry.
Now, with the Token Curated List Dapp and our agreement with Ethfinex, the stakes are much higher, and we want jurors to have the best experience possible.
In this article we’ll go over some of the ways we innovated across the stack, starting with the smart contracts and back end infrastructure, and finishing with the user interfaces.
The first version of the Kleros smart contracts had some painful limitations in user experience and functionality:
- All disputes shared the same lifecycle. This meant disputes had to wait for the next session before starting.
- Jurors had to transfer their tokens before staking them.
- The way juror stakes were being stored made it so that you could not edit your stake, only set it at the start of each session and then, after it was reset at the end of the session, set it again. This meant jurors had to come back every session to maintain their stake. Drawing also did not happen on chain, so notifying jurors of their draws required iterating over all staked tokens, something that could quickly become unviable.
- There was no support for commit and reveal or our planned governance backed subcourt hierarchy.
Phasing and Periodization
The first improvement was pretty obvious. We needed a global phase for enabling the economy of scale aspect of staking, generating a random number, and then drawing using the random number. This is necessary so people can not set up their stake in a way that benefits them during drawing.
The lifecycle of disputes however, can be dispute specific. This lets the courts work on-demand and disputes start and end in parallel. This also makes disputes finish faster, because in certain periods, you can advance without waiting for the full duration. For example, you can pass the vote period early if everyone has already voted.
To solve the second issue, all we needed to do was make the main contract the token controller of the Pinakion Minime Token contract. This allows it to block transfers that would make a juror insolvent during redistribution.
Stakes, Sums, and Trees
Staking was a bit harder to solve. We needed a way to efficiently edit a mapping of addresses to numbers, and be able to draw randomly from them efficiently. Stakes were being stored as a set of ranges, we needed a better data structure. It turns out that the not so well documented sum trees were perfect for this task.
We wrote about the approach here. This turned out to be a great idea and Aragon went on to implement it as well. We also threw in delayed execution of stake edits for when it’s not the staking phase. The user interface views can just run them eagerly and the user doesn’t have to know or think anything about phases at all.
Subcourt Governance and Hidden Votes
Instead of having one global court, we created a tree of courts. The shape of the tree and the parameters of each court can be modified through the governance system, and one of these parameters is whether or not voting in the court should use commit and reveal or not, a key feature for high stake disputes.
We have bots for listening to events and triggering email webhooks, and one for executing action callbacks in contracts like delayed set stakes or period passes. We also set up an IPFS node for resilient storage of off chain data as per the evidence standard.
Another key innovation was our approach to batch sending and execution of delayed set stakes. We came up with a new algorithm for doing this in a much more efficient way than previously done. This made action callback bots much cheaper and resilient to gas price hikes.
With the smart contract improvements out of the way, we turned to developing the user interface. We started by radically changing our previous architecture to achieve a way better developer experience and performance. Then we came up with a few simple protocols to make the user experience of authentication for things like notification settings and other off chain data storage seamless.
Drizzle and Hooks
We wanted the interface to be really performant, but not at the expense of less decentralization that comes with indexing servers. Trufflesuite’s Drizzle provided a great way of managing on chain data with aggressive caching that is only invalidated when the contracts receive new transactions.
We ended up improving the developer experience and performance by writing a hooks module for it that ended up being merged into the package. This came with some nice extras, like cached dynamic event querying, that the library did not originally have.
No More Lost Salts
Lots of applications that need to generate salts for commit and reveal games have suffered from the bad user experience of having to store or remember your random salt input to the hashing function.
Users have sometimes cleared their browser cache or switched computers and then lost assets due to not being able to reveal their commits. We came up with a way to solve this by deriving a secret from a user’s signature that can then be stored and used as a source of entropy for salt generation.
This means that when the user clears or loses his cache, it can still generate the same salt again. Pretty neat right?
Seamless Off Chain Auth
We applied a similar technique to authenticating off chain CRUD operations. For this we used the secret to derive an account that gets registered to the main account’s settings through a signed payload. After the initial registration, the interface can sign operations with the derived account without asking for permission. This is great for stuff like notification settings and other non critical data.
You can even share the secret you use for salt generation and account derivation so that users are only ever requested their signatures once per fresh browser launch.
We still have lots of exciting planned features and community requests that we are getting ready for the coming months. Also, keep tuned for new integrations with some great projects in the community.
Join the community chat on Telegram.
Visit our website.
Follow us on Twitter.
Join our Slack for developer conversations.
Contribute on Github.