Note: This is an unfinished document and is meant to provide an overview over one of Sure’s solutions. It is written in the public to allow anyone to easily contribute or come with critique of the product.
An oracle on Solana
As a part of Sure the goal was to be able to prove on-chain that a breach has happened and how much was lost.
Most on-chain insurance platforms relies on a committee to decide claim payout. This might be a good as a first solution. However, this is too fragile and introduce trust.
It is necessary to have an on-chain oracle that can answer arbitrary questions. These questions might be in the context of insurance like
- “How much was lost on <protocol/pool> at 12/08/22?”
Or more fun ones like
2. “Will Brazil win the world cup?”
The answer to 1. would typically be between 0 and infinite while for 2. it is a “yes” or “no” answer.
For a generalized oracle the answer should always be between 0 and infinite (or u256). However, it is up to the proposer and voter to agree on the range. For 1. it could be 0 and infinite and for 2. it could be 0 (“no”) and 1 (“yes”).
The oracle solution mimics the game of guessing the number of marbles in a concealed but transparent tube — the best guess is the average.
The pros of having the vote on-chain is that everything is transparent, the con is that it’s transparent. Yes, you read that right. Although everyone can validate the result and review the code, everyone can also find out the current voting distribution. Since voters should be rewarded for their information discovery it is not fair that anyone can just copy the answers of the super predictors. Or at least not in this version.
The actors in the protocol are
- Proposer — the person who propose a vote
- Voter — a person who want to affect the result
The oracle program flow is supposed to be pretty simple.
- propose_vote: the proposer proposes a vote.
- submit_vote: with the hashed vote. The salt used to generate the vote should be stored securely.
- update_vote or cancel_vote: a user can in the voting window update their vote
- reveal_vote: after the voting period has concluded the user can submit their vote and salt. The program will then make a hash comparison to determine whether it’s the same vote. The voter does not have to reveal their vote.
- finalize_vote_results: after the reveal period is over the proposer can finalize the vote. It is not possible to reveal the vote after this.
- finalize_vote: this allows the voter to calculate their result. See more under rewards.
- collect_proposer_reward: if the vote is successful the proposer can collect its reward.
- collect_vote_reward: the voter can collect their reward.
Now there are a couple of methods used in this flow that needs addressing.
In order for the voter to keep their vote as private they should hash their vote using a salt before submitting the vote. Since the reward or yield on voting is determined by how far you are from consensus the voter is incentivized to keep their vote a secret.
Worst case scenario is that the user leaks the salt which allows anyone to read their vote before the reveal period starts.
Rewards are used to incentivize people to do information discovery. It’s basically a salary. The preciseness of the vote result is a function of the reward.
The rewards needs to come from somewhere. It’s not possible to print imaginary money, or it is but it has little value to a serious voter.
The rewards should come from bad information searchers or adversaries.
From the oracle perspective users just pool money, votes on what they believe is the truth and receives a cut of the pool money based on performance. The question naturally arises, but how do you distribute the pool money after a successful vote?
An important part of the oracle is the distribution of rewards. In this context the distribution is how far the vote is off the consensus.
We can assume that the distribution of votes are normally distributed
The payout function could therefore be exponential as a function of (v_i — V)^2 where V is the consensus and v_i is the vote. This is also why the flow contains so many steps.
When reveal period is over the parameter of the exponential distribution can be estimated. By default, if your vote is spot on, (v_i — V)² = 0, then your reward would be 1.5x ( the parameter can be changed through governance).
After the parameter is estimated the voters can calculate their distribution and collect the rewards. If you vote faaaar from the consensus you would naturally receive less than what you put into the pool.
Now, what do you vote with or how is vote power decided.
One way is to use a vested escrow.
A voted escrow allows users to lock their tokens over a longer period of time to increase their vote power. This prevents any adversary to buy up all tokens (voting power), vote far away from every “honest” voter and receive all the rewards. Essentially stealing the vote pool.
Currently, the proposed oracle is implemented in full on Solana in the Sure repository. Although being almost feature complete it’s still in alpha.
Maybe the core of the implementation is getting the distribution in the end right. With Solanas tight compute budget it’s necessary to estimate the parameter of the payout model efficiently. Luckily there’s a closed form solution to the scale parameter of the exponential model, namely
and to calculate the voter reward weight
Please see the code for a more detailed description of the mathematics
Sure will leverage the oracle to build a risk protocol on top. The risk exposure will be provided as perpetual options where the underlying is the result of a vote.
Improvements / versions
Instead of having the voter approve a bunch of steps in the program flow, it could be possible to determine rewards based on the tuple (vote,time) instead of just (vote). This remove the need for a hashed vote since you would be rewarded for voting before anyone else.
However, this would open up for payout optimizoooors to just vote the same as consensus.