-
Notifications
You must be signed in to change notification settings - Fork 7
feat: goo (gno optimistic oracle) #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Intermarch3
wants to merge
14
commits into
gnoverse:main
Choose a base branch
from
Intermarch3:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
24677ba
add: goo (gno optimistic oracle)
Intermarch3 15d24a3
fix: remove natspec doc
Intermarch3 91e0309
fix: render functions
Intermarch3 b7a5176
fix: var type errors
Intermarch3 6ed3498
fix: errors and Leon's comment
Intermarch3 69790d9
fix: format
Intermarch3 618501a
test: add a part of the oracle tests
Intermarch3 c7a7d93
add: oracle unit tests
Intermarch3 561610f
fix: format and more
Intermarch3 31fc552
fix: exposed vars security issue
Intermarch3 3b197cb
fix: format
Intermarch3 3107cbe
fix: review comments
Intermarch3 1dd0262
refacto: use pointer in avl tree
Intermarch3 681a1ef
fix: format
Intermarch3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| .idea | ||
| .idea | ||
| .DS_Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| # Gno Optimistic Oracle (GOO) | ||
|
|
||
| An Optimistic Oracle (GOO) built on Gno.land. This system is designed to bring external data onto the blockchain by leveraging game-theoretic incentives. It assumes data is correct unless disputed, hence the term "optimistic." | ||
| This implementation is inspired by the [UMA Optimistic Oracle](https://uma.xyz/) but adapted for the Gno ecosystem. | ||
|
|
||
| ## Table of Contents | ||
| - [Core Concepts](#core-concepts) | ||
| - [How It Works: The Lifecycle of a Data Request](#how-it-works-the-lifecycle-of-a-data-request) | ||
| - [Architecture](#architecture) | ||
| - [User Roles](#user-roles) | ||
| - [Tokenomics](#tokenomics) | ||
| - [Usage Example](#usage-example) | ||
| - [Developer](#developer) | ||
|
|
||
| ## Core Concepts | ||
|
|
||
| The Gno Optimistic Oracle operates on the principle that data proposed to the oracle is assumed to be true. A bond is required for any new proposition. This proposition enters a "liveness" period where anyone can dispute it by posting an equal bond. | ||
|
|
||
| - **Happy Path**: If no one disputes the data within the liveness period, it is considered resolved and accepted as truth. The proposer's bond is returned along with a reward. | ||
| - **Unhappy Path (Dispute)**: If the data is disputed, OOT (Optimistic Oracle Token) Holders can vote on the correct outcome. This is handled by the `court.gno` contract. Token holders vote, and the outcome is decided by the total token weight backing each value. The winner's bond is returned, and they receive a portion of the loser's slashed bond. | ||
| See [Tokenomics](#tokenomics) to understand how to get an OOT. | ||
|
|
||
| ## How It Works: The Lifecycle of a Data Request | ||
|
|
||
| The entire process, from requesting data to its final resolution, follows a clear, multi-step path. | ||
|
|
||
| ### 1. Data Request (`RequestData`) | ||
| A user or a contract initiates a request for data by calling `RequestData`. | ||
| - **Ancillary Data**: A clear, human-readable question (e.g., "What was the price of ETH/USD at block X?"). | ||
| - **Type**: The request can be a `Yes/No` question (represented by 0 and 1) or a `Numeric` value. | ||
| - **Reward**: The requester must lock a `RequesterReward` in GNOT to incentivize a proposer to provide the data. | ||
| - **Deadline**: The requester sets a deadline by which the data must be proposed, otherwise they can retrieve their locked reward. | ||
|
|
||
| ### 2. Value Proposal (`ProposeValue`) | ||
| A **Proposer** provides an answer to the request. | ||
| - They call `ProposeValue` with the proposed answer. | ||
| - They must post a `Bond` in GNOT, which is held in escrow. | ||
| - This action starts the **Resolution Time**, a liveness window during which the proposal can be disputed. | ||
|
|
||
| ### 3. The Liveness Period | ||
| Once a value is proposed, a countdown begins. During this period, anyone can challenge the proposed value. | ||
|
|
||
| - **If Undisputed**: If the `ResolutionTime` expires without any disputes, the request is considered final. Anyone can call `ResolveRequest`. The `ProposedValue` becomes the `WinningValue`. The Proposer gets their bond back, plus the `RequesterReward`. | ||
| - **If Disputed**: If another user believes the proposed value is incorrect, they can challenge it. | ||
|
|
||
| ### 4. Dispute (`DisputeData`) | ||
| A **Disputer** can challenge the Proposer's value. | ||
| - They must call `DisputeData` before the `ResolutionTime` ends. | ||
| - They must also post a `Bond` equal to the Proposer's bond. | ||
| - This action pauses the request's resolution and initiates a formal dispute, handled by the `court.gno` contract. | ||
|
|
||
| ### 5. Voting (`VoteOnDispute`) | ||
| The dispute is now open for voting by all OOT holders. The system uses a **commit-reveal scheme** to prevent vote-copying. | ||
|
|
||
| - **Commit Phase**: During the `DisputeDuration`, voters submit a hash of their vote (`SHA256(value + salt)`) by calling `VoteOnDispute`. They must also pay a small `VotePrice` fee. | ||
| - **Reveal Phase**: After the commit phase ends, the `RevealDuration` begins. Voters must call `RevealVote`, submitting their original `value` and `salt`. The contract verifies that the hash matches the one submitted during the commit phase. | ||
|
|
||
| ### 6. Dispute Resolution (`ResolveDispute`) | ||
| Once the reveal period is over, anyone can call `ResolveDispute`. | ||
| - The `resolver.gno` contract tallies the votes. The winning value is the one with the highest cumulative token weight from voters. | ||
| - The `WinningValue` is set in the original `DataRequest`. | ||
| - **Slashing & Rewards**: The party (Proposer or Disputer) that lost the vote has their bond slashed. The winning party gets their bond back, and the slashed bond is distributed among the voters who voted for the winning outcome (voters who vote incorrectly lose 25% of their Oracle Token balance). | ||
|
|
||
| ## Architecture | ||
|
|
||
| The oracle contract is composed of three main files: | ||
|
|
||
| - `oracle.gno`: Manages the data request lifecycle (request, propose, dispute, resolve). It is the main entry point for users. | ||
| - `court.gno`: Handles the entire dispute resolution process, including the commit-reveal voting scheme. | ||
| - `resolver.gno`: Contains the business logic for tallying votes and determining the winning value of a dispute. It supports both Yes/No and Numeric resolutions. | ||
|
|
||
| ## User Roles | ||
|
|
||
| - **Requester**: The user or contract that needs external data. They create the request and fund the reward. | ||
| - **Proposer**: The user who provides the initial answer to a data request and posts a bond. | ||
| - **Disputer**: A user who challenges a proposed value and posts a bond to initiate a vote. | ||
| - **Voter**: An Oracle Soulbound Token holder who participates in a dispute by voting on the correct outcome. | ||
|
|
||
| ## Tokenomics | ||
|
|
||
| The token (OOT) is a non-transferable token that represents voting power in the oracle system. | ||
| - **Acquisition**: Users can acquire OOT by calling `BuyInitialVoteToken` and paying a fee in GNOT. This action mints one OOT to the caller's address (can only buy 1 initial token). | ||
| OOT holders can participate in disputes and earn rewards by voting correctly. By voting correctly, they can earn a portion of the slashed bonds from losing parties and gain 2 Vote tokens, incentivizing accurate and honest participation in the oracle system and increasing their voting power. | ||
| - **GNOT Usage**: The reward and the Bond (in GNOT Token) need to be less than the bond to avoid trying to game the system by creating disputes just to earn tokens, as they would lose more from the bond than the reward. | ||
| This design is not final and can be adjusted based on community feedback and economic analysis. | ||
|
|
||
| ## Usage Example | ||
|
|
||
| Here is a full workflow using `gnokey`. | ||
| **0. Buy OOT for Voter Role (one time action)** | ||
| ```bash | ||
| # Buy Oracle Soulbound Token (replace <voter-key-name> with your key name) | ||
| gnokey maketx call -pkgpath "gno.land/r/intermarch3/goo" -func "BuyInitialVoteToken" -gas-fee 1000000ugnot -gas-wanted 10000000 -send "1000000ugnot" -broadcast -chainid "dev" -remote "tcp://127.0.0.1:26657" <voter-key-name> | ||
| ``` | ||
|
|
||
|
|
||
| **1. Request Data** | ||
| ```bash | ||
| # Ask a Yes/No question: "Will ETH be below $4000 ?" (replace DEADLINE_TIMESTAMP with a future unix timestamp more than 24h from now) | ||
| gnokey maketx call -pkgpath "gno.land/r/intermarch3/goo" -func "RequestData" -args "ETH below 4000$ ?" -args "true" -args "DEADLINE_TIMESTAMP" -gas-fee 1000000ugnot -gas-wanted 10000000 -send "1000000ugnot" -broadcast -chainid "dev" -remote "tcp://127.0.0.1:26657" <your-key-name> | ||
| ``` | ||
|
|
||
| **2. Propose a Value** | ||
| ```bash | ||
| # Propose "Yes" (value 1) (replace ID with the actual ID returned from the RequestData call) | ||
| gnokey maketx call -pkgpath "gno.land/r/intermarch3/goo" -func "ProposeValue" -args "ID" -args "0" -gas-fee 1000000ugnot -gas-wanted 10000000 -send "2000000ugnot" -broadcast -chainid "dev" -remote "tcp://127.0.0.1:26657" <proposer-key-name> | ||
| ``` | ||
|
|
||
| **If no one disputes within the liveness period, anyone can resolve the request:** | ||
| ```bash | ||
| # Resolve the request (replace ID with the actual ID) | ||
| gnokey maketx call -pkgpath "gno.land/r/intermarch3/goo" -func "ResolveRequest" -args "ID" -gas-fee 1000000ugnot -gas-wanted 10000000 -send "" -broadcast -chainid "dev" -remote "tcp://127.0.0.1:26657" <any-key-name> | ||
| ``` | ||
|
|
||
| **3. Dispute the Value** | ||
| ```bash | ||
| # Dispute the proposal (replace ID with the actual ID) | ||
| gnokey maketx call -pkgpath "gno.land/r/intermarch3/goo" -func "DisputeData" -args "ID" -gas-fee 1000000ugnot -gas-wanted 5000000 -send "2000000ugnot" -broadcast -chainid "dev" -remote "tcp://127.0.0.1:26657" <disputer-key-name> | ||
| ``` | ||
|
|
||
| **4. Vote on the Dispute** | ||
| First, generate a hash locally. Let's vote "No" (value 0) with salt "mysecret". | ||
| Hash: `sha256("0" + "test")` -> `a96e0beb59a16b085a7d2b3b5ffd6e5971870aa2903c6df86f26fa908ded2e21` | ||
| ```bash | ||
| # Commit the vote (replace ID with the actual ID) | ||
| ggnokey maketx call -pkgpath "gno.land/r/intermarch3/goo" -func "VoteOnDispute" -args "ID" -args "a96e0beb59a16b085a7d2b3b5ffd6e5971870aa2903c6df86f26fa908ded2e21" -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" -broadcast -chainid "dev" -remote "tcp://127.0.0.1:26657" <voter-key-name> | ||
| ``` | ||
|
|
||
| **5. Reveal the Vote** | ||
| ```bash | ||
| # Reveal the vote after the voting period ends (replace ID with the actual ID) | ||
| gnokey maketx call -pkgpath "gno.land/r/intermarch3/goo" -func "RevealVote" -args "ID" -args "0" -args "test" -gas-fee 1000000ugnot -gas-wanted 10000000 -send "" -broadcast -chainid "dev" -remote "tcp://127.0.0.1:26657" <voter-key-name> | ||
| ``` | ||
|
|
||
| **6. Resolve the Dispute** | ||
| ```bash | ||
| # After the reveal period, anyone can trigger the final resolution (replace ID with the actual ID). | ||
| gnokey maketx call -pkgpath "gno.land/r/intermarch3/goo" -func "ResolveDispute" -args "ID" -gas-fee 1000000ugnot -gas-wanted 10000000 -send "" -broadcast -chainid "dev" -remote "tcp://127.0.0.1:26657" <any-key-name> | ||
| ``` | ||
|
|
||
| When testing with `gnodev` locally, ensure to make transactions between waiting periods as `gnodev` only creates blocks when a transaction is made, and the oracle relies on current block timestamps. | ||
|
|
||
| ## Warning | ||
|
|
||
| This is a simplified example for educational purposes. In a production environment, consider additional security measures, optimizations, and edge cases. | ||
|
|
||
|
|
||
| ## Developer | ||
|
|
||
| | [<img src="https://github.com/intermarch3.png?size=85" width=85><br><sub>Lucas Leclerc</sub>](https://github.com/intermarch3) | | ||
| | :---: | | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A nice addition would be to suggest (and maybe even build) a Go program to suggest values using gnoclient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#20