Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
A decentralized truth machine
An optimistic oracle (OO) that can record any verifiable truth or data onto a blockchain 🔮
UMA is an optimistic oracle and dispute arbitration system that securely allows for arbitrary types of data to be brought onchain. UMA’s oracle system provides verified onchain data for projects including:
Crosschain bridge
Prediction markets
Insurance protocols
Custom derivatives
UMA's optimistic oracle (OO) is designed to be modular and extensible with focus on building real-world use cases. Two main versions of the optimistic oracle (OO) are currently live: OOv2 and OOv3. Choosing the right one depends on your use case.
Learn the fundamentals of UMA's optimistic oracle.
UMA offers OOv2 and OOv3. Based on your idea and product, let's learn which one fits your use case best:
We understand that your product needs can be complex and would require a larger discussion on which optimistic oracle version to use. Feel free to reach out to us and get help.
Having decided the correct optimistic oracle for your use case, let's now dive deeper into how you can ship apps powered by verifiable onchain truth using UMA's optimistic oracle.
OOv2 prioritizes protocols that need third-parties to propose answers to data requests.
Here are some app guides to help you build on UMA OOv2:
OOv3 prioritizes protocols that simply needs asserted data to be verified.
Here are some app guides to help you build on UMA OOv3:
The UMA token secures UMA’s optimistic oracle through decentralized governance and economic guarantees against corruption. Token holders vote on upgrades, price requests, and disputes, earning rewards for honest participation.
UMA Improvement Proposals (UMIPs) are design documents used to propose changes to the UMA ecosystem. They are an important part of UMA's governance processes.
The UMA DAO accepts proposals for onchain actions that require tokenholders approval. An example would be a request for funding from the UMA treasury.
We request all community members and developers to and gain instant help on any issues they face while voting or submitting proposals to UMA.
You can .
The security of our protocol is extremely crucial. If you notice any bugs in the protocol, . You can also find details of our .
This section showcases different design patterns for building contracts that integrate with the UMA Optimistic Oracle (OO). These include:
A simple deposit box to showcase the basic OO request lifecycle.
An event based prediction market. In this example, settlement requests are submitted at the time of contract deployment, and the OO proposer network is used as a decentralized keeper service that identifies when settlement events happen and propose the outcomes.
An , where an integrating contract handles proposals and state management, and only uses the OO when proposal verification is needed or a dispute is filed.
Keep up with the latest updates to UMA’s Optimistic Oracle. This changelog covers new features, improvements, and important changes for developers and integrators.
Integrations must submit data requests that can then be answered by third-party proposers.
Integrations submit assertions, where they propose data to their own request along with its parameters.
The specific parameters for proposers and disputers to follow must be included in the request.
The challenge period and dispute process remains the same.
Primary use cases: Prediction markets, sports betting applications, and insurance protocols.
Primary use cases: Crosschain infrastructure, content moderation, transaction verification.


Prediction Market
Use OOv2 to identify and settle real-world events in prediction markets.

Insurance
Use OOv2 to verify and resolve claims in insurance applications.

Data Asserter
Use OOv3 to asserts arbitrary offchain data onchain through flexible assertions

Escalation Managers
Use OOv3 to enable modular functionality via custom escalation managers

Governance
Learn about UMA token, UMIPs and voting on UMA's DVM

UMIP Process
Learn how UMIPs propose changes to the UMA Ecosystem

DAO Proposals
Learn how you can submit onchain proposals to the UMA Ecosystem
Increased the Settlement Price Approval Threshold (SPAT)
The Settlement Price Approval Threshold (SPAT) is basically the level of agreement needed among voters to resolve a dispute. Before now, the OO used to accept a simple majority (50%+), which meant disputes could be resolved, even on rare occasions when opinions were pretty divided.
We’ve now raised SPAT to 65% to strengthen the required consensus for vote outcomes. If we don't hit that threshold, the vote "rolls" to another round, giving everyone time to reconsider and discuss until there’s a stronger community agreement.
Enhanced Voter Information and Warnings
We've added clear warnings and guidance for voters within the dApp to help voters understand that they have a responsibility to verify claims independently.
Improved Discussion Environment
We've updated how discussions are sorted in the voter dApp; instead of the initial chronological order where the earliest comments are seen first in the discussion pane, users can now sort from the most recent
Fixed PM Market Linking
We've resolved technical issues with links to Polymarket markets, ensuring voters can easily access the associated market information directly from the voter dApp. This provides crucial context about market odds and trading activity.
Using a token that allows backlisting (e.g. USDC) as your currency opens up a griefing vector that integrators should be aware of.
The and functions allow the caller to set any address as the proposer and disputer that will receive payouts if their proposal/dispute is correct upon settlement. If a bad actor calls both and and specifies a blacklisted address for repayment, the function will revert and cause the request to be frozen unless the address is unblacklisted. This costs the malicious user 2 bonds and does not result in any gain, but freezing the request could cause issues for the integrator.
To avoid this, integrations that use tokens with blacklisting functionality should ensure that their admins can call a function that ignores the frozen request and creates a new OOV2 request. In this way they can prevent a frozen request from having any negative consequences to their protocol.



Risk Labs currently provides gas rebates for voters who have staked 1000 or more UMA to encourage more community members to participate in securing the Optimistic Oracle.
Rebates cover the gas cost for commit and reveal transactions and are denominated in ETH.
Voters must have at least 1000 UMA staked at the start of the commit period for that voting period's commit and reveal transactions to be rebated.
Commited votes must be revealed to be rebated.
If a voter commits more than once on a dispute, only the first commit will be rebated.
If a delegate address is used to vote, the rebate will be sent to the delegate address.
Rebates are calculated for one calendar month and are sent out within the first half of the following month. Announcements are made in the UMA Discord at the time each rebate is sent out.
LLM generated Discord discussion summaries warnings and information
The Voterdapp contains a "Discussion Summary" tab with an LLM summary of Discord comments on the vote. The summary removes duplicate arguments across all comments to give voters an overview of all arguments which is useful for long or spammed comment threads. The summary does not fact check comments, add additional arguments, or give voting recommendations.
Voters should always verify all arguments included in the summaries with their own research. The raw comments are also provided in the "Discord Comments" tab so voters can review them against the summary in case of LLM error.
Using a token that allows backlisting (e.g. USDC) as your assertTruth currency opens up a griefing vector that integrators should be aware of.
The assertTruth and disputeAssertion functions allow the caller to set any address as the asserter and disputer that will receive payouts if their assertion/dispute is correct upon settlement. If a bad actor calls these functions and specifies a blacklisted address for repayment, the settle function will revert and cause the request to be frozen unless the address is unblacklisted. This costs malicious users their bonds and does not result in any gain, but freezing the assertion could cause issues for the integrator.
Integrations that use tokens with blacklisting functionality should ensure that they have a way to manage frozen assertions (e.g. an admin function that can ignore a frozen assertion) without negatively affecting their integration.
Support for oSnap will be deprecated on December 15th, 2025. After this date, oSnap will not be able to execute transactions from your DAO’s Safe treasury.
oSnap integrations should take the following steps to prepare:
Ensure their Safe signers are prepared to sign and execute any necessary DAO transactions
Disable oSnap on all DAO treasuries by following these steps: https://docs.uma.xyz/developers/osnap/disabling-osnap
The ManagedOptimisticOracleV2 contract is modified version of the OptimisticOracleV2 intended to be deployed for a single integration. It allows the integration to designate a request manager address that can set a default proposer whitelist and easily manage an existing request's bond size, liveness and proposer whitelist before the request has been proposed.
UMA's Optimistic Oracle allows contracts to quickly request and receive data information. The Optimistic Oracle acts as a generalized escalation game between contracts that initiate a price request and UMA's dispute resolution system known as the Data Verification Mechanism (DVM). Prices proposed by the Optimistic Oracle will not be sent to the DVM unless it is disputed.
If a dispute is raised, a request is sent to the DVM. All contracts built on UMA use the DVM as a backstop to resolve disputes. Disputes sent to the DVM will be resolved within a few days - after UMA tokenholders vote on what the correct outcome should have been.
The first part of UMA's oracle system is the Optimistic Oracle. This is a layer that is designed to optimistically verify pieces of data quickly. It is secured by the UMA DVM, because disputes can be escalated from the Optimistic Oracle layer to the DVM for dispute arbitration. The main lifecycle of the OO looks like this, and is detailed in the Asserter and Disputer rows within the diagram above.
Risk Labs manages the default proposer whitelist for Polymarket's ManagedOptimisticOracleV2 contract. The current whitelist can be viewed and is subject to updates and changes in guidelines. Polymarket, as the request manager for the contract, may also change an unproposed request’s proposer whitelist at any time.
Proposer addresses must meet the two below criteria over the last 6 months:
5 or more Polymarket proposals on OptimisticOracleV2 or ManagedOptimisticOracleV2
oSnap Proposal Verification with UMA's Optimistic Oracle
After transactions have been requested for execution, the challenge period begins. The challenge period length is set by the oSnap Safe module advanced settings. Invalid requests must be disputed within the challenge period. oSnap requests can be reviewed in the 's Verify tab.
After selecting a request, a sidebar will show additional request details including the bond amount, when the challenge period ends, a dispute button (when a wallet is connected), a link to the corresponding Snapshot proposal, the oSnap rules that the request should be reviewed against (including minimum quorum and voting period for the Snapshot proposal), and links to relevant block explorer pages.
Steps to remove oSnap from your DAO Snapshot space and Safe treasury
Requirements:
The below steps propose a Safe transaction to disable oSnap. Transactions can only be proposed to a Safe by that Safe's Signers or Proposers. You can view these roles on your Safe's settings page.
Executing the proposed Safe transaction requires your minimum number of Signers to sign the transaction and one Signer to execute the transaction.
Steps:
Additional tutorials and resources about UMA that are not featured on this docs site
Internal Learning Sessions
Go to the , if you are disputing proposals on a live network like Ethereum, Optimism, or Polygon, or go to the if you are disputing test data on Görli. Disputes will be resolved by the if you are on a live network, or by a mock oracle if you are on Görli (see Resolving Disputes).
Locate proposals under the Proposals tab for outstanding proposals that are within the challenge window and can be disputed.
Click on the proposal you want to dispute.
As of December 8th, 2025. is the intended default identifier to be used with OOV3. The original identifier will be deprecated as of December 15, 2025. These identifiers have teh same specifications and the change is only to break support for deprecated projects.
Please note: after these changes do not use the following OOV3 functions:
the assertTruthWithDefaults function will always revert as it hardcodes in the ASSERT_TRUTH identifier
the defaultIdentifier public constant variable will return the deprecated ASSERT_TRUTH identifier
Viewing, proposing and disputing ManagedOptimisticOracleV2 requests on the Oracle Dapp is the same as other OptimisticOracleV2 requests except for the following differences:
If your connected address is not on the request's proposer whitelist, the propose button on the request's sidebar will be disabled.
The request's proposer whitelist is displayed under the "More Information" heading at the bottom of the request sidebar.
Risk Labs/UMA protocol no longer actively supports or improves:
The
The
These contracts are open-source code, and anyone is free to use, improve, or fork the code. However note that for these contracts to be safe, it requires a robust system of well capitalized off-chain watchers (liquidator & disputer bots) to continually check that positions are appropriately collateralized, or that positions are not being liquidated unfairly. Anyone using this code in production must ensure that there are well-capitalized liquidators and disputers running at all times; failure to do so could result in a loss of all locked funds. Risk Labs does not and will not run liquidators for these contracts, nor does it give any security assurances about any EMP or Perp contracts. As always, UMA protocol and Risk Labs will continue to support proposed addition or request of price identifiers for general use including within EMP/Perp contracts.
Voting best practices and warnings
Read through the vote Description under the Details tab. Carefully review how the vote should resolve and if provided, the timing of when the request can resolve and any listed sources.
Review the Timestamp under the Details tab. This is the point in time at which the vote should be evaluated.
The vote Discussion tabs lists comments from the UMA Discord with arguments, resources, and suggested votes that may be helpful. However, some commenters may try to influence the vote for their own profit. Always independently verify any claims before relying on them.
This section showcases different design patterns for building contracts that integrate with the UMA Optimistic Oracle v3. These include:
A showcasing the simplest possible OOv3 integration contract.
Building example contracts:
Proposing and disputing ManagedOptimisticOracleV2 requests is largely the same as OptimisticOracleV2 requests with the following differences:
Programmatic proposers and disputers will be used to listening for OptimisticOracleV2 events and sending proposing and disputing transactions to these addresses. To add support to new ManagedOptimisticOracleV2 deployments, programmatic proposers and disputers will have to add these new deployment addresses to their bot configs.
Note: the first ManagedOptimisticOracleV2 deployment is managed by Polymarket and can be found .
For prediction market votes, it is helpful to review the market odds over time to sanity check your vote. The market odds after an event has expired are a reflection of how bettors with skin in the game think a market should resolve. You should not vote based on the market odds, but if you are planning on voting against strong market odds you may want to do extra research to ensure your vote is correct.
Proposal accuracy greater than 95% in the last 6 months.
Propose OOV2 Polymarket requests that are not whitelisted to meet the criteria for the next update.
Updates are based on data pulled on the 2nd of each month for the preceding 6 months (e.g. June 2nd to December 2nd). The whitelist is updated within the following week.
Yes, if a whitelisted address no longer meets the criteria of the most recent update it will be removed from the whitelist.
Click the 'Connect wallet' button in the top right corner and go through the steps to connect your wallet. Confirm you are on the same network as the proposal.
Before disputing, confirm the details of the request and ancillary data to ensure the proposal is actually incorrect. You may also want to check the instructions in the UMIP for the identifier.
Click the 'Dispute Proposal' button.
Confirm the transaction details through your wallet provider. After confirming, the proposal will be disputed.
If you are on a live network, the dispute will escalate to the DVM on Ethereum for resolution. If you are on Görli, you will need to manually resolve the dispute through the Mock Oracle.
When a project integrates with UMA, they do so with the understanding that someone is always watching for the opportunity to dispute bad proposals. The Verification Team is one form of defence against these bad proposals, and an important one at that. This team is responsible for bringing the human element to proposal resolution. Sometimes the truth can only be discovered through intensive research and lengthy discussion. Our job is to highlight those moments and provide the best source of truth available for UMA voters to consider. By joining our team, you become a key contributor to our shared goal of maintaining the integrity of our oracle.
Join the Verification Team here --> https://discord.gg/muN6tBaG4d
If you are interested in working at UMA, please see our vacancies below. If you know someone that might be a good fit, check out our “talent referral options” program that offers up to 1000 $UMA to anyone who refers suitably qualified candidates for any of our open positions.
ManagedOptimisticOracleV2 requests have defined proposer whitelists. The whitelist for a given request can be found by calling the getProposerWhitelistWithEnforcementStatus function with the request's requester , identifier , and ancillaryData. The function will return an isEnforced boolean that defines whether a whitelist is enforced and an address array of allowedProposers . If isEnforced is true, then only allowedProposers may propose the request. If isEnforced is false, any address will be able to propose.
When a new request is created on ManagedOptimisticOracleV2 it will default to the defaultProposerWhitelist unless overridden by the requestManager . This default whitelist can be viewed with the following steps:
Call the defaultProposerWhitelist view function on a deployed ManagedOptimisticOracleV2 contract to get the address of the default whitelist.
Call getWhitelist on the default whitelist address to view all address on the whitelist. Alternatively, call isOnWhitelist to check if a given address is on the whitelist.
Proposing on ManagedOptimisticOracleV2 can be done by calling the same proposePrice or proposePriceFor functions with the same arguments as proposing on OptimisticOracleV2. Proposal transactions from addresses that are not whitelisted will revert with the following error messages, "Sender not whitelisted" or, "Proposer not whitelisted".
The emitted events that are relevant to oracle participants (RequestPrice, ProposePrice and DisputePrice, SettlePrice) are unchanged from the OptimisticOracleV2 contract. These events can be queried via RPCs or by using our subgraph that indexes ManagedOptimisticOracleV2 events.
An Asserter will post a bonded assertion about the state of the world. This assertion will :
identifier: price identifier being requested.
timestamp: timestamp of the fact being asserted.
claim: ancillary data containing additional information about the assertion
currency: ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.
bond: a bond size that represents the stake the asserter is putting on their statement being correct.
Disputers can refute a piece of data submitted by an Asserter within the assertion liveness period by referencing their own off-chain price feeds and determination methodologies. The liveness period is a pre-defined amount of time a that an assertion can be disputed.
If Disputers do not refute the price submitted by the Asserter within the proposal liveness period, the assertion is optimistically treated as being correct.
If an assertion is disputed, the assertion will be submitted to UMA’s DVM for dispute arbitration.
The Data Verification Mechanism (DVM) provides a backstop to the UMA OO by resolving disputes that happen when a proposed/asserted piece of data is disputed.
In the event of a dispute, a price request is submitted to the DVM which proposes a vote to UMA tokenholders to report the price of the asset at a specific timestamp.
The vote will conclude after a 48-96 hour voting period.
UMA tokenholders will reference the price identifier's UMIP to determine how to arrive at a vote result via off-chain price feeds and methodologies.
The DVM will aggregate votes from UMA tokenholders to determine the final price of the asset for a given timestamp.
The DVM is powerful because it encompasses an element of human judgment to ensure contracts are securely and correctly managed when issues arise from volatile (and sometimes manipulatable) markets.
UMA's oracle system is constructed with economic guarantees around the cost of corrupting the DVM to ensure it will cost more to corrupt the oracle (i.e., obtain 51% or more UMA tokens) than the amount someone could profit from corrupting the oracle (i.e. stealing funds within contracts on UMA).

UMA Improvement Proposals (UMIPs) are design documents used to propose changes to the UMA ecosystem. UMIPs are intended to be the primary mechanism for proposing new features, collecting community input on an issue, and for documenting the design decisions that have gone into the UMA protocol.
UMIPs are a convenient way to track the progress of an implementation. Examples of common UMIPS include adding a new price identifier or collateral currency to be supported by the DVM. UMIPs are presented to UMA tokenholders for voting through the voting dapp to determine whether they will be accepted or rejected.
UMIPs need to provide a concise technical specification of the feature and a rationale for the feature. They are modeled after EIPs and ZEIPs. See here for an EIP template and ZEIP template.
If the dispute is on a live network, it will be resolved by the DVM on Ethereum, and the results returned within 48-72 hours (depending on when the dispute was raised during the DVM voting cycle).
If you are testing the dispute flow on Görli, you will need to manually resolve the dispute through the Mock Oracle. This contract stands in for the DVM on Görli and allows you to manually return your own values for testing purposes.
Go to the Mock Oracle contract on Görli Etherscan.
Click 'Write Contract.'
Click 'Connect to Web3' to connect your wallet.
Click 'OK' on the pop-up that warns you that writing to contracts on Etherscan is a beta test feature.
Connect through your wallet interface, and switch networks to Görli if necessary.
Click pushPrice to see the parameters you will need to enter.
Enter the original request's identifier, time, and ancillaryData, and enter the value you want to return for price.
Click 'Write' and submit the transaction.
Depending on how the contract you are testing was written, you may need to call settleAndGetPrice from your contract to the Optimistic Oracle contract to get the value returned from the mock oracle, or you may be able to call settle on the Optimistic Oracle and have your contract automatically receive and handle the return value with a priceSettled callback function.
A description of Escalation Managers and how they can be used.
Deploying sandboxed oracle environment for testing the dispute flow.
An oSnap proposal's voting results must meet both criteria below to be considered passed:
Quorum: FOR + AGAINST + ABSTAIN ≥ Required Quorum
'FOR' majority: FOR > 50% * (FOR + AGAINST + ABSTAIN)
If the oSnap request does not meet the Rules, it should be disputed. Disputed requests can not be executed no matter how UMA resolves the dispute. This section outlines the steps to dispute an invalid oSnap request, or any other invalid assertions to UMA's Optimistic Oracle.

Click "Execution" on the left side menu and the pencil icon inside the "oSnap by UMA" box to show oSnap enabled Treasuries.
If your space has oSnap configured, Treasuries will display below the "oSnap by UMA" box with their status displayed as "Active".
To disable oSnap on a active oSnap treasury, hover over "Active", to show the "Disable" button and click it to open the oSnap Safe app.
Opening up the oSnap Safe app may bring up the following Safe warnings depending on your browser's stored cookies:
In the oSnap Safe app, click "Deactive oSnap"
This will propose a "disableModule" transaction in the Safe(Wallet) dapp. This transaction can be proposed, reviewed, signed, and executed as per the typical Safe(Wallet) transaction flow.
After this transaction is executed, oSnap is disabled from your Safe treasury. Treasuries without oSnap enabled will display with an "Enable" button in Snapshot's Execution settings page (note, it may take some time after the executed transaction for the Snapshot UI to update).
ManagedOptimisticOracleV2 requests are tagged "Managed Optimistic Oracle V2" on the Oracle Dapp.


Overview of Setting Customer Bond and Liveness Parameter in UMA's Optimistic Oracle
Every request to UMA's Optimistic Oracle includes bond and liveness settings that specify the size of the bond that proposers (and disputers) are required to post, the token used for bonding, and the liveness window, which is the challenge period during which a proposal can be challenged.
The minimum bond is the same as final fee for Optimistic Oracle V2 (OOV2) or can be queried by calling getMinimumBond(token) for Optimistic Oracle V3 (OOV3). The default liveness window is two hours. For many cases, you may want to customize these values. The primary reason to increase the bond size or challenge window is to increase your security for complex requests or requests that could move large amounts of money.
In most cases, you will want to set a bond higher than the minimum. The reason for this is that the bond provides a financial incentive for disputers to dispute invalid proposals. Disputers receive half of the proposer bond in the case of a successful dispute in the OOV3. For the OOV2, it's half of the excess above the final fee.
The part of the bond that doesn't go to the disputer in a successful dispute goes to the UMA Store contract. The reason the disputer does not get the full amount is to prevent a malicious proposer from making a bad proposal and then front-running an honest disputer to dispute themselves if they get caught.
As an example, imagine an application that requires a 10,000 USDC bond to assert a claim via OOV3.
To make an assertion, a proposer must post a 10,000 USDC bond, which they will get back after the liveness window if the assertion is not disputed. To make a dispute, a disputer must also post a 10,000 USDC bond.
If the disputer wins, they receive 15,000 USDC (10,000 USDC disputer bond + 5,000 USDC from the excess proposer bond) and the Store receives 5,000 USDC.
If the proposer wins, they receive 15,000 USDC (10,000 USDC proposer bond + 5,000 USDC from the disputer bond) and the Store receives 5,000 USDC (half of the disputer bond).
If data received from the oracle could potentially move large amounts of value, you may want to set a higher bond to make it more costly for an attacker to attempt to steal funds through a false proposal. (Remember that the proposer will lose their entire bond if they are disputed and found to be incorrect.)
The tradeoff to setting a higher bond is that it may be more difficult to run a project that requires frequent proposals, since good proposers will have funds locked up for at least the length of the challenge window. Another tradeoff is that a very high bond may make it difficult for disputers to post bonds to challenge bad proposals. Remember also that disputers will lose their bond if they are incorrect, so the disputer has a capital cost and a risk of loss.
Before launching your contract, you should think about who you expect to be proposers and disputers, whether they have adequate access to capital, how much value the oracle is securing, how many requests you expect to make in a given day, and whether you should add a proposer reward (to incentivize independent proposers to take on the capital cost and risk of proposing answers to your requests).
There are no exact answers to how high or low your bond should be, although it is almost always a good idea to set a bond that is larger than the final fee so that disputers have an incentive to dispute bad proposals.
The liveness period is the challenge window where disputers can dispute a proposal, and is another knob you can turn to increase security (while accepting UX trade-offs).
A typical challenge period is two hours, which is usually plenty of time for disputers to recognize and dispute bad proposals. In some cases, you may want to increase the length of the challenge period. A classic example is an insurance contract, since insurance contracts usually have these qualities:
Large amounts of value are at stake.
Payouts are rare.
Proposals and disputes require a greater amount of thought and consideration.
Payouts are not very time sensitive, and a long delay (even a day or more) to allow proposers and disputers to think through the situation will not seriously inconvenience users.
You may want to consider a two-hour challenge window in these situations:
Requests happen frequently and proposers and disputers will need to reuse their capital regularly for bonding.
The dollar value secured by a request is lower.
The request is easy to reason about (and proposals and disputes could potentially be automated).
Users are sensitive to the settlement time.
At this time, it is generally not recommended to set a challenge window shorter than two hours.
If your users are very sensitive to settlement time, you may want to consider a smart contract architecture that allows a particular type of user to fully insure a piece of data that is acted on instantly, and then waiting to be reimbursed after the challenge window. Think of this user as a "designated waiter," who is probably compensated in some way.
A good example is the in the Across protocol. Users of the Across bridge receive their funds almost instantly, because a relayer sends them funds on the receiving chain and then submits for reimbursement from the protocol, and has to wait for several hours for their relay to be bundled with other relays, proposed, and then settled after the challenge window.
In this case, the UX for most users is excellent (nearly instant transfers) but the protocol is still secured by a long challenge window that is absorbed by a less time sensitive user type (the relayer) who is paid fees for their trouble.
The UMA token is primarily a governance token used to contribute to UMA protocol decisions, such as voting on UMA Improvement Proposals (UMIPs), price requests, and disputes made to UMA's Data Verification Mechanism (DVM).
The UMA token is an integral part of the UMA ecosystem as it guarantees the economic security of UMA smart contracts and its oracle system. The objective of the UMA token is to enable the optimistic oracle to remain secure utilizing a fully decentralized and permissionless method.
UMA's DVM is designed with an economic guarantee around the cost it would take to corrupt the oracle and the profit someone would receive. The DVM ensures the price to obtain 51% of UMA tokens is greater than the profit from corrupting the DVM, as measured by the collateral stored in UMA's financial contracts. This is achieved through an inflationary reward (currently 0.05% of total network token supply), distributed pro-rata by stake to voters who participate and vote correctly. As long as there is an honest majority, voters will vote correctly.
As the total value of collateral locked in UMA grows, the UMA token is required to increase in value to ensure the security of the DVM. To ensure this inequality holds, the DVM may charge fees to financial contracts which the DVM would use to buy UMA tokens.
The UMA voting process requires tokenholders to commit and reveal their votes in two separate stages. Each stage is open for 24 hours, so each voting period is 48 hours.
UMA Tokenholders can discuss their votes in the #voting channel of the before voting
UMA tokenholders can use the to vote on protocol decisions
Examples of governance proposals include:
Approving new and
Price requests and disputes
Upgrading the core DVM protocol and / or modify DVM parameters
Registering and de-registering contract templates
This tutorial describes how to propose answers to data requests. The data could be anything from token prices, to who won a basketball game, to whether an optimistic governance action is valid.
Step 1: Go to the Optimistic Oracle dApp, if you are answering requests on a live network like Ethereum, Optimism, or Polygon, or go to the Testnet dApp if you are answering requests (probably your own) on Goerli.
Step 2: Locate requests under the Requests tab for outstanding requests.
Step 3: Click on the request you are interested in proposing data for.
Step 4: Click the 'Connect wallet' button in the top right corner and go through the steps to connect your wallet. Confirm you are on the same network as the data request.
Step 5: Before proposing, confirm the details of the request and ancillary data to ensure you are proposing accurate data. You may also want to check the instructions in the for the identifier.
Step 6: Once you are sure of the proposed value and connected to your wallet, input the value and click the 'Submit Proposal' button.
Step 7: Confirm the transaction details through your wallet provider. After confirming, the proposal will be sent!
The "Optimistic Oracle" (OO) allows contracts to quickly request and receive price information. Unlike mechanically restrictive price feed oracles, an optimistic oracle can serve any arbitrary data on-chain.
The “Data Verification Mechanism” (DVM) is the name of the oracle service provided by UMA. The DVM does not provide an on-chain price feed. Instead, it is only used to resolve disputes of liquidations and to settle synthetic token contracts upon expiration.
The financial product libraries are used to transform the value returned by the price identifier into a final settlement value. Financial product libraries can be applied to create different types of financial contracts and payout functions.
Refer to for a list of deployed financial product libraries for each network. If your desired financial product library is not already deployed, refer for instructions on deploying and verifying your own financial product library contract.
The collateralPerPair parameter determines the amount of collateral required to mint each pair of long and short tokens.
Example: If a contract uses WETH as collateral and the collateralPerPair parameter is set to 0.25 on deployment, each long and short token that is minted would require 0.25 WETH as collateral.
ExpiryPercentLong is used to determine the redemption rate between long and short tokens. ExpiryPercentLong is a number between 0 and 1, where 0 assigns all collateral to the short tokens and 1 assigns all collateral to the long tokens.
Range tokens enable a DAO to use its native token as collateral to borrow funds. At maturity, if the debt is not paid, the range token holder is instead compensated with an amount of the collateral (the native token) using the settlement price of the native token to determine the number of tokens. This is similar to a tokenized convertible debt structure.
Success tokens offer an alternative way for DAOs to diversify their treasury and sell tokens to investors in an incentive-aligned way. Success tokens are two financial products wrapped into one token: a set amount of a project token which is combined with a covered call option on that token backed by a set amount of the same token.
Key Performance Indicator (KPI) Options are synthetic tokens that will pay out more rewards if a project’s KPI reaches predetermined targets before a given expiry date. Every KPI Option holder has an incentive to improve that KPI because their option will be worth more. This is intended to align individual token holder interests with the collective interests of the protocol.
The UMA DAO accepts proposals for on-chain actions that require tokenholders approval. An example would be a request for funding from the UMA treasury. The steps to complete a proposal:
Step 1: Post to Discourse
The first step is making a post in the UMA discourse under non-technical UMIPs. The post should outline the key components of a proposal and give the community a chance to submit feedback and recommend changes.
An example submission is Polymarket's Liquidity Mining Program.
Step 2: Snapshot Vote
When the proposal appears ready, a Snapshot vote can be created by the proposer with a 5 day close. Should it receive majority support at the end of 5 days, it will then pass to snapshot for an indicative vote prior to being put to an on-chain vote.
Proposals that require movement of treasury funds require a 4,000 UMA bond to be posted which is returned if the proposal is successful in an on-chain vote of tokenholders.
RiskLabs, the foundation which established UMA, has indicated its willingness to handle the on-chain proposal and cover the bond payment for proposals which attract majority support on a snapshot poll of tokenholders.
Here is the snapshot for .
Step 3: On-chain Vote
After a Snapshot vote has successfully passed, an on-chain vote is held to transfer the funds. If the vote is successful, the funds are transferred to the recipient wallet address.
Integrations use the Optimistic Oracle for various use cases.
For a complete list of all current integrations see:
This table includes identifiers that could be useful for new contracts and are likely to be encountered by proposers, disputers, and voters. It does not include identifiers that have been deprecated, identifiers that have fallen out of use, or specific token pairs.
If you need an identifier that is not included in this list, you can for approval. If a price request is made with an identifier that is not on this table, please refer to the canonical on GitHub. The absence of an identifier from this table does not necessarily mean the identifier is not approved, it just means it is not recommended for new contracts.
If you want to use an approved identifier that is not on this list, let us know and we can add the identifier back to this table for easier voter/disputer reference.
This section explains the UMA subgraph and how to interact with it. The UMA subgraph indexes data from UMA contracts over time. It organizes data about tokenholders, contracts, DVM requests, voting, and more. The subgraph updates for each UMA contract interaction. The subgraph runs on protocol’s hosted service and can be openly queried.
UMA has a GraphQL API Endpoint hosted by called a subgraph for indexing and organizing data from the smart contracts. The schema of GraphQL elements available is defined in .
How to stake tokens, vote, and claim rewards
This tutorial describes how to vote using the . For context, each voting period is 48hrs. Voting takes 3 steps:
Commit Vote: the first 24hrs of a voting period allows you to encrypt and commit your vote
Reveal vote: the second 24hrs of a voting period allows you to decrypt and reveal your vote. Votes are tallied by a DVM smart contract at the end of the reveal period.
Shutting down contract instantiations (in rare circumstances)
Graphql Endpoint: https://gateway.thegraph.com/api/[api-key]/subgraphs/id//41LCrgtCNBQyDiVVyZEuPxbvkBH9BxxLU3nEZst77V8o
LSP Subgraphs
EMP Subgraphs (includes query for whitelisted collateral)
Voting Subgraphs
Here is the source code for deployed subgraphs.
To learn more about querying a subgraph refer to The Graph’s documentation.














Sherlock is a protocol on the Ethereum blockchain that protects users from smart contract exploits with proprietary security analysis and protocol-level coverage. UMA acts as an unbiased, decentralized arbiter for Sherlock where disputes are escalated to UMA's DVM and voted on to be resolved.
Domination Finance is a decentralized exchange (DEX) deployed on Ethereum and Polygon. Domination Finance uses UMA's Optimistic Oracle to enable users to speculate on popular market dominance metrics, such as Bitcoin Dominance (BTCDOM).
Yam Synths is a powerful platform from the Yam DAO community providing easily accessible and innovative synthetic assets. UMA's Optimistic Oracle helps Yam to allow anyone in the world to access and trade cutting-edge synthetic products.
Hats.finance is a proactive bounty protocol for white hat hackers and auditors, where projects, community members, and stakeholders incentivize protocol security and responsible disclosure. Hats.finance and UMA have collaborated on a product called protected tokens which enable users to recover funds in the event of a hack, bug, or other cause of lost funds.
Across protocol is a novel bridging method that combines UMA's Optimistic Oracle with bonded relayers and single-sided liquidity pools to provide decentralized instant transactions from rollup chains to Ethereum mainnet.
Polymarket is an information markets platform that lets you trade on the world’s most highly-debated topics. Polymarket supports UMA and its Optimistic Oracle as a resolution source for its markets.
Jarvis Network is a set of protocols on Ethereum allowing anyone to gain exposure to the price of any traditional or digital assets with stablecoins, against liquidity pools. Jarvis leverages UMA's Optimistic Oracle and DVM as its liquidation and dispute mechanism to ensure that jFIATs are properly collateralized.
ASSERT_TRUTH2 (as of Dec 8, 2025)
New intended default price identifier for Optimistic Oracle V3
MULTIPLE_CHOICE_QUERY
Allows requests with a predefined set of valid responses.
NUMERICAL
Returns a number value based on a question asked in the ancillary data.
ROPU_ETHx
Reflects violations of the MEV-policy committed by validators of the ETHx staking protocol
YES_OR_NO_QUERY
Returns an answer to a "yes or no" question.
ACROSS-V2
Verification of whether a bundle of Across bridge transactions submitted to mainnet is valid.
ASSERT_TRUTH (DEPRECATED as of Dec 15, 2025)
Former default price identifier for Optimistic Oracle V3
The purpose behind using the Commit/Reveal scheme is that it allows votes to remain private.
Go to http://vote.uma.xyz.
Connect your wallet.
In order to vote, you must stake your tokens. Click "Stake/Unstake" then follow the instructions in the module. Staking your tokens does three things:
Your tokens will immediately start to earn a prorated portion of the $UMA token emissions, which is reflected as an APY on the dapp.
You will be able to vote with those tokens
You will have a 7-day cooldown period in order to unstake those tokens. During that period, your tokens will not be earning any rewards or be eligible for voting.
You can only vote when there is a live vote(s), and during the Commit period.
Choose your vote(s) from the dropdown menu, then click "Commit vote" and send the transaction.
Each voting round consists of a 24-hour commit period, followed by a 24-hour reveal period. In order for your vote(s) to count, you need to return and reveal your vote(s) during the reveal period.
During the reveal period, return to the Dapp and choose "Reveal" to reveal your vote(s).
Once the dapp shows your vote as "Revealed," you are done with the voting process. The vote(s) will be finalized when the reveal period ends, at which point you will be able to see if you voted correctly. If you did, you will receive a bonus. If you voted inaccurately or failed to vote, you will have a penalty applied to your stake. This penalty amount is redistributed to accurate voters.
Protocol Parameters (adjustable by governance)
Emissions: .18 $UMA/second
Missed vote penalty: 0.1% of staked balance
Withdraw cooldown period: 7 days
Emission rewards begin to accrue automatically when you stake $UMA. You may claim these rewards to your wallet, or claim-and-stake to your staked balance.
Rewards associated with voting successfully are automatically added to your staked balance after the voting period ends.
How to verify Polymarket Proposals
The YES_OR_NO_QUERY (UMIP can be read here) is a price identifier intended for plaintext binary questions. Requesters encode their questions in ancillary data. For a full overview of how ancillary data is formatted, refer here.
The YES_OR_NO_QUERY is most typically used by Polymarket today to resolve the outcome of information markets. This can come in the form of asking for the outcome of sports games, a crypto or nft price at a specific point in time or world events among many other things.
Note that this price identifier is often in the form of YES or NO, but could also be in the form of THIS or THAT - ie “did the Lakers or Clippers win the game last night” can work even though it is not really a YES or NO question. The example used in the rest of this document will illustrate how this can be done.
From the UMIP:
When converted from bytes to UTF-8, the ancillary data should be a dictionary object containing q (question), p1, p2, p3 and p4 keys and values. p4 is optional and will only apply in certain situations.
Example:
q: title: French Open Final: Djokovic vs. Ruud, description: This market will resolve to "Djokovic" if Novak Djokovic wins the final, or to "Ruud" if Casper Ruud wins the final. res_data: p1: 0, p2: 1, p3: 0.5. Where p1 corresponds to Ruud, p2 to Djokovic, p3 to unknown/50-50,initializer:91430cad2d3975766499717fa0d66a78d814e5c5
The UMIP goes on to note default values for p1, p2, p3 and p4.
p1 is usually used for “NO” values and defaults to `0` if not explicitly assigned
p2 is used for “YES” values and defaults to `1` if not explicitly assigned
p3 is for “UNKNOWN” or “CANNOT BE DETERMINED” and defaults to `0.5` if not explicitly assigned.
p4 is for situations where the question is expected to eventually be able to be evaluated, but cannot be at this time. An example would be if the outcome to a sports game was asked for, but the game has not yet happened or finished. This will be referred to as the “magic number” and defaults to the minimum int256 value or before e18 scaling: -57896044618658097711785492504343953926634992332820282019728.792003956564819968
Important Note: Polymarket currently uses OptimisticOracleV2. Therefore, the early request should only be used if a proposed value is proposed earlier than the expected event resolution time noted in ancillary data.
For additional context on when the magic number or p3 are expected to be returned, from the UMIP:
p4 is intended to be used for situations where it is not a given that the price request (or contract settlement) should even occur yet. An example of this would be the UMA event-based expiry LSP. A request to settle an event-based expiry LSP can be submitted at any time but if the question can not be resolved yet it should be ignored.
The default p4 value is the minimum int256 value and is used as a "magic number" to indicate that an event-based expiry request is invalid and the contract should continue as normal. For example, if the question is related to a basketball game on January 6th and a settlement request comes in on January 5th, the question can not be resolved yet, and voters should return the p4 value with the magic number to reject the settlement request. This value also moves the decimal place 18 spaces to the left, due to the default behavior of the UMA voting interface to scale input values to 18 decimals. After scaling by the interface, the value will be -57896044618658097711785492504343953926634992332820282019728792003956564819968
Notice that a p3 value would never be returned earlier than the final price request time noted in the ancillary data or the requesting contract's expiration timestamp and a p4 value would never be returned after that point. Consider an unresolvable question like, "Was the weather nice on January 6th, 2022?" If the question was asked on January 7th, 2022, you would return the p3 value. If the same question was asked on January 5th, 2022, you would return the p4 value.
Also noted in the UMIP is the fact that return values are not scaled when referred to in the UMIP or present in ancillary data.
This simply means that if the ancillary data contains “p2:1”, this should really be returned on-chain as 1e18 (not 1 wei). So 1000000000000000000 instead of 1.
All price identifier values are treated this way in the UMA system. The UMA voter dapp and Optimistic Oracle proposer interface both perform this scaling automatically for UMA voters or proposers.
When verifying a proposal, it is important to assess the question data and arrive at their own conclusion for what the return value should be. Here is the example above in the oracle UI:
Key data in the proposal is the identifier, timestamp, and the ancillaryData.
The YES_OR_NO_QUERY identifier tells us which “pricing methodology” we should be referring to. This is best understood by reading the corresponding UMIP. For all price identifiers, the UMIP can be looked up by price identifier name.
The proposed time tells us the timestamp a value was proposed and therefore should be evaluated.
The Additional Text Data above represents the ancillary data and contains the plaintext version of the binary question that a proposer should be evaluating. It is important to read the full text data as it could also contain pricing specifications or data sources that should be used.
In the example, I can see that the question is asking if Novak Djokovic or Casper Ruud wins the French Open Final. It does not specify a data source so I can use a wide array of publicly available information to determine what I think the correct answer should be. Referring to ESPN scores:
I see that Djokovic won and I should continue to read the ancillary data to determine which return value should be used in this scenario.
Ancillary data question:
This market will resolve to "Djokovic" if Novak Djokovic wins the final, or to "Ruud" if Casper Ruud wins the final.
Resolution key:
res_data: p1: 0, p2: 1, p3: 0.5. Where p1 corresponds to Ruud, p2 to Djokovic, p3 to unknown/50-50
Since Djokovic won and p2 corresponds to 1, the proposed value should be p2:1.
Voters/proposers should typically evaluate all price requests independent of the party that has requested the data. But as a validation tool, the requestor can sometimes provide information that will help us verify the values that we are about to propose. As an example, this question was from .
This is one simple example of evaluating a YES_OR_NO_QUERY, but almost all questions follow the same format.
ABT
0.055
USDB
250
The UMA DVM two-key contract enables you to actively engage in voting using hot keys (private keys stored on machine and used often), but protect your funds with the stronger, and preferable, use of cold keys (private keys stored offline and used rarely). Another way this contract can be used is to delegate voting rights to an EOA, while still maintaining token ownership with a multisig or other ownership structure.
Each two-key contract is a unique smart contract that you deploy. It keeps track of:
The number of UMA tokens you have deposited into the two-key contract
The address of your hot wallet; the hot wallet is permissioned to sign transactions and vote in DVM governance
The address of your cold wallet; only the cold wallet (and importantly, not the voting wallet or any other address) is permissioned to withdraw UMA tokens from the two-key contract
DANGER
If you do not know exactly why you are setting up a 2-Key contract, then you likely do not need one. Deploying the contract is expensive and unnecessary unless you need to vote with separate hot and cold keys.
Voting with a hardware wallet is not a reason that necessitates needing to set up a 2-Key contract. You can likely vote by connecting your hardware wallet to MetaMask or another wallet provider.
If you have any doubt about your need for a 2-Key contract, please ask in the UMA Discord before proceeding.
You need ETH in your hot wallet for the initial deployment of the 2-key contract and for submitting all subsequent votes.
You need ETH in your cold wallet to make the initial UMA token deposit, and also if you ever want to withdraw tokens from the 2-key contract.
Navigate to the UMA voter dApp (vote.umaproject.org) and connect your MetaMask hot wallet. This will be your voting wallet going forward.
Click on the gear icon on the far right.
In the modal, click Add Cold Wallet Address
Input your cold wallet address and click Save.
The following steps help you verify that your two-key contract was deployed correctly and check that the permissions are held by the correct address.
Copy the 2-key smart contract address (i.e., DesignatedVoting Escrow Account) from the voter dApp and view it on Etherscan
Under Read Contract input roleID 0 in function 1. getMember, and click query. Check that the address output matches your cold wallet address.
Input roleID 1
To vote with the 2-key contract, you will need to send UMA tokens to it. After sending UMA tokens to the two-key contract address, you can immediately start voting with your hot keys at the voter dApp. This will exclude you from voting with any additional UMA tokens that are in your hot wallet through the voter dApp.
The following steps let you withdraw UMA tokens from the two-key contract using your cold keys. You will have to withdraw and deploy a new two-key contract if you want to designate a new hot key for voting.
Navigate to your DesignatedVotingContract on Etherscan
Connect your cold wallet by clicking the “Connect to web3” button
Use function 11. withdrawErc20
Changing the voter address
To change the voter address for a DesignatedVotingContract, you just need to call resetMember(newAddress) with your cold keys (owner address) and pass in the new address that you wish to use as the voter.
Frequently asked questions about the new UMA DVM 2.0
To learn more about how exact APY is calculated, you can refer here.
At a high level though, all UMA voters on average will receive an APY determined by the annual UMA emissions amount divided by the average total UMA staked over the year.
Before the DVM 2.0 upgrade, approximately 18-20mm UMA was voting on average for each vote. If this holds relatively constant, it means that average UMA voter APYs will be approximately 28-32%. This can of course fluctuate on an individual voter basis dependent on voter performance.
Maximizing your APY should be simple. To maximize APY you should:
Remain staked within the system.
Claim and restake your rewards at times when it makes sense based off balancing your increased stake’s additional future rewards received against gas costs of claiming and restaking.
Vote consistently and carefully. Incorrect or absent voter stakes are slashed and distributed to correct / participating voters after each voting round.
The UMA emission rate is currently 0.155 UMA/second. This will be distributed pro-rata to all stakers within the UMA system on a per second basis. The UMA emissions rate is controlled by UMA governance and can be updated at any time by a DVM vote.
The unstake timer is a set amount of time that a staker must wait before they can execute a request to unstake from the UMA system. With the initial DVM 2.0 upgrade, this unstake timer was set to 7 days.
The unstake timer exists to make the UMA voting system more hardened against attempted manipulation attacks. UMA has always had an assumption that if a malicious attacker could manage to either vote with or bribe a majority of voters to vote incorrectly on a dispute, the UMA token would go to zero in value. This is known as the UMA cost of corruption.
In practice, this is probably not entirely true as markets are not entirely efficient. Attackers could likely dump voted with tokens for some amount of value after a successful attack. Having a required 7 hold period more strongly enforces that UMA’s cost of corruption is enforced by the market if a manipulation attempt is successful.
The Optimistic Oracle & DVM can provide all kinds of different data, from crypto prices, to sports, to verifying if a bridging transaction was valid, with new use cases being added all the time, so its hard to anticipate precisely what you might be asked to vote on, however all questions will be asking something about the state of the world at a particular time, indicated by the timestamp.
There are two primary data sources to assist a voter in determining what value they should vote with.
First, the UMIP that the DVM request references. This will tell you general information about how that question should be answered. The second place to check is the ancillary data of the question. This will provide more context for the question and is likely to include a source, which a link that will take you to a place where that data is likely to be published.
Disputes are also discussed at length in the #voting-chat and #evidence-rationale channels.
The commit/reveal cycle prevents people from seeing how others have voted by encrypting all initial votes and only decrypting them once all votes are cast. The oracle is built on Schelling Point theory, which indicates that the most likely consensus of non-colluding participants is the truth. By obscuring how other people have voted, this ensures that each tokenholder votes independently.
No. Only tokens that have been staked can be voted with. If you have already initiated the unstaking process for any or all of your coins, they also will not receive rewards or be able to be voted with. However if you have unstaked coins when a vote starts, you can stake your coins any time up to the end of the commit period, and they will be eligible to vote with.
Unstaked tokens cannot vote. This includes tokens that are in the “cooldown period” after an unstake request has been submitted.
You cannot. Unstake requests cannot be canceled once submitted. If you once again wish for those tokens to be staked, you can wait for the unstake period to finish, claim your tokens and restake them.
It is possible to delegate your staked UMA in one wallet to a different wallet, allowing voters to keep their UMA on a cold wallet and vote with hot wallet, however there is a 1-1 relationship between voting wallets and staking wallets, therefore it is not possible for one person to vote on behalf of multiple other people.
Yes! Risk Labs will still be continuing with the existing voting gas rebate program.
Jump into our and ask questions about anything that you are unsure of.
0 to 1 Optimistic Oracle integration by example.
The primary integration point into the UMA ecosystem is the Optimistic Oracle (OO). The OO is an oracle for arbitrary off-chain data which leverages an interactive escalation game between requesters, proposers and disputers and is secured by economic incentives.
This getting started tutorial will show you how to go from 0 to 1 with the Optimistic Oracle by executing the simplest possible request flow. Later in the docs you can find more information on and dig deeper into its mechanism and .
0 to 1 integration with the Optimistic Oracle V3.
The primary integration point into the UMA ecosystem is the Optimistic Oracle V3 (OOV3). The OOV3 is an oracle for arbitrary off-chain data which leverages an interactive escalation game between asserters and disputers and is secured by economic incentives. It differs from the Optimistic Oracle V2 (getting started can be found ) by being easier to reason about and simpler in integration points.
This getting started tutorial will show you how to go from 0 to 1 with the OOV3 by executing the simplest possible assertion flow. Later in the docs you can find more information on how the OOV3 works and dig deeper into its mechanism and more sophisticated code examples.
1. getMember0x04fa0d235c4abf4bcf4787af4cf447de572ef828Input the number of tokens that you want to withdraw * 10^18 (for example, if you want to withdraw 1.1 tokens, you should input 1100000000000000000)
Click “Write”
Confirm the transaction with your cold keys and wait for the transaction to finish mining
USDC
250
WETH
0.055
WIP
50

You will be working through a simple smart contract that asks the oracle the question: Q:Did the temperature on the 25th of July 2022 in Manhattan NY exceed 35c? A:1 for yes. 0 for no. After submitting the request, you will propose a solution using the UMA Optimistic Oracle UI.
Once through liveness, you will fetch the price from the smart contract. This shows the full lifecycle of an Optimistic Oracle data request on the Sepolia testnet, interacting with an actual Optimistic Oracle contract deployment, without needing to write any code or clone any repos. It should give you the basic intuition as to how the Optimistic Oracle works without too much overhead and is a great starting point before digging deeper. Let's get started!
To complete this tutorial you will need:
Metamask installed in a Chromium based browser (such as Google Chrome) If you don't have it already, you can get Metamask here.
A wallet set up in Metamask.
Sepolia test ETH to send test transactions. You can get Sepolia ETH from one of these faucets: Infura, Alchemy, PoW Faucet, or LearnWeb3,
First, we will work through the basic flow for asking the oracle for a piece of data. In this example, we are asking the Oracle for information on the weather but the request could be much more complex to could power any kind of smart contract system requiring data. See approved price identifies and the sample projects for more inspiration on what is possible with the OO.
The contract used in this tutorial is meant to be a simple data request flow. The contract exposes a simple requestData function which asks the OO a simple question about the weather.
Go to this example contract on Remix. This gives you the minimum data request and retrieval flow possible. We'll work through the code in the sections that follow.
Click on "gist-fba..." to see the files in the gist, and click OO_GettingStarted.sol to open to Solidity file.
In the far left hand menu, click the link to deploy and run transactions (which looks like the Ethereum logo and a right arrow).
In the "Environment" dropdown, choose "Injected Provider," and connect to your wallet. Make sure you are connected to Sepolia within your Metamask wallet! You don't want to deploy to a real network and spend real gas, and the Sepolia Optimistic Oracle address hardcoded into the contract will not work on other networks.
Under the "Contract" dropdown, select OO_GettingStarted.
Click "Deploy" and confirm the transaction with your wallet.
You should now see the OO_GettingStarted contract under "Deployed Contracts". Clicking the dropdown carrot will reveal buttons for each of the functions in the contract.
Click requestData to request the data specified in the contract's ancillary data, asking about the temperature in Manhattan on July 25th, 2022. Confirm the transaction in your wallet. This will submit a data request to the Optimistic Oracle.
What we've done in the above steps is: a) deploy a smart contract and b) submit a "price request" to the Optimistic oracle through the call to the Optimistic Oracle's requestPrice function.
Now that we've asked the OO a question, it's time to propose a solution! The Optimistic Oracle works via an interactive escalation game wherein a) requesters ask questions b) proposers provide solutions and c) disputers monitor the proposals and dispute if they are invalid. If no dispute is done then the proposal is taken as valid. In this example, we'll be acting as the proposer who will be answering the question we asked in the previous section
Go to the Sepolia Optimistic Oracle UI to see your request, which should be a YES_OR_NO_QUERY at the top of the index page. Click on the request to go to the details page.
Click "Connect Wallet" and make sure you are connected to the Sepolia testnet so that you can make a proposal. You should see all the information posed in the data request: the requester, identifier, timestamp, ancillary data and a link to the UMIP.
Submit your proposal (either 1 or 0). The actual value you submit is not super important in this case since this is just for testing purposes, but the is 0. In doing this we are acting as the "proposer" providing a solution.
Once you've provided an answer to the question the proposal enters into a liveness period of 30 seconds. During this time it's up to Disputers to verify the correctness of what the proposer provided. Note that in a main net price request you'll normally set the liveness to much longer than 30 seconds (say two hours), the proposer will be bonded (if they propose wrong they lose money) and the proposer will be rewarded for providing a valid answer to the question.
Finally, we can fetch the data proposed in the previous step from the smart contract. For this example, we assume that there the proposed data was correct (was not disputed). Head back to your Remix tab and:
After the transaction finalizes, wait 30 seconds (the challenge window) and then click settleRequest on the OO_GettingStarted contract on Remix. Confirm the transaction in your wallet. Because the proposal was not disputed within the challenge window, it can now be settled.
Click getSettledPrice to get the settled value. It should look like int256: 0 under getSettledPrice if you proposed an answer of 0. You can also see details in the console logs.
Congratulations! you've successfully integrated with the Optimistic Oracle, requested data, proposed data and fetched it within your smart contract! Note that the incentives in this toy example mean that there is no reason that anyone would provide the correct price (there was no reward for the proposers or disputes and there was no bond). A real world version of this should leverage custom bonds and more realistic liveness parameters.
Hopefully you got a basic understanding of the OO request flow from this getting started guide. Check out some of the example tutorials where we walk through more details on the functions discussed in this guide.
The OOV3 works by making a truth claim about the world, stating that something has happened or is true. Once asserted, the assertion enters a challenge period wherein someone can disagree with the assertion, by disputing it. If no one disputes it during the challenge window the statement is taken as true. If disputed, the outcome is arbitrated using the UMA DVM (more info on how this works here).
In this tutorial you will be working through a simple smart contract that asserts the following truth: Statement: Argentina won the 2022 Fifa world cup in Qatar.
Once through the challenge window, you will use the assertion in your resolution contract. This shows the full non-dispute lifecycle of an OOV3 data assertion. It will give you the basic intuition as to how the Optimistic Asserter works without much overhead and is a great starting point before digging deeper. Let's get started!
To complete this tutorial you will need:
Metamask installed in a Chromium based browser (such as Google Chrome) If you don't have it already, you can get Metamask here.
A wallet set up in Metamask.
Görli test ETH to send test transactions. You can get GETH from Alchemy's faucet.
First, we will work through the basic flow for asserting a truth to the oracle. In this example, we are making a statement about the outcome of a sports event, but the statement could be much more complex; it could power any kind of smart contract system requiring data.
The contract used in this tutorial is meant to be a simple data assertion flow. The contract exposes a simple assertTruth function which asserts the truth to the OA about the outcome of the world cup.
Go to this example contract on Remix. This gives you the minimum assertion flow. Read the contract and the comments listed within.
In the far left hand menu, click the link to deploy and run transactions (which looks like the Ethereum logo and a right arrow).
In the "Environment" dropdown, choose "Injected Provider," and connect to your wallet. Make sure you are connected to Görli within your metamask wallet, that has Görli test ETH! You don't want to deploy to a real network and spend real gas, and the Görli Optimistic Oracle address hardcoded into the contract will not work on other networks.
Under the "Contract" dropdown, select OOV3_GettingStarted.
Click "Deploy" and confirm the transaction with your wallet.
You should now see the OOV3_GettingStarted contract under "Deployed Contracts". Clicking the dropdown carrot will reveal buttons for each of the functions in the contract.
Click assertTruth to request the data specified in the contract's ancillary data, asserting the truth about the outcome of the Fifa world cup. This will submit a data assertion to the Optimistic Asserter and the assertion will enter the challenge period.
What we've done in the above steps is: a) deploy a smart contract and b) submit a "data assertion" to the Optimistic Oracle V3 through the call to the Optimistic Oracle V3's assertTruthWithDefaults function. Now, the assertion has entered the challenge window and can be disputed by someone who disagrees with the assertion. If you click the getAssertion you can see some of the fields that are associated with the assertion. For more details on what these fields mean you can look at the OOV3 interface here.
The default liveness for an assertion is 120 seconds (2 minutes). Wait this time before going to the next step.
Once the assertion has settled, and assuming no one has disputed it, we can settle it! Do the following:
Click settleAndGetAssertionResult in remix. This will send a transaction to settle the assertion and return the settlement value.
Wait for the transaction to mine.
Once mined you can expand the transaction output block inline with the green tick arrow. If you scroll down here you can find some information about the assertion, such as the settlement value (which should be true as it was not disputed).
Now, you can call getAssertion and getAssertionResult from remix and see the outputs. getAssertion has changed such the settled value is true and getAssertionResult now returns true as the assertion was deemed valid as it was not disputed.
Hopefully you got a basic understanding of the Optimistic Oracle V3 request flow from this getting started guide. Note that this kind of example would not really work on mainnet as: a) there were no bonds for the asserter (and therefore no rewards for disputers) b) the challenge window was too short. The Optimistic Oracle V3 works due to economic incentives between the asserter and disputers, which was absent in this example to keep things simple. For some incentive compatible examples check out some of the example tutorials where we walk through more details on the functions discussed in this guide. Those can be found here.
How to verify Across Bundles
Step 1: Install Required Dependencies:
git:
Documentation: https://github.com/git-guides/install-git
yarn:
Documentation: https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable
node.js
Documentation:
Run the following command to check what version of node you are running: node -v
Make sure it is greater than 16.18.0.
redis:
Documentation:
Note: Follow the instructions
ts-node
You can use the following to install globally: npm install -g ts-node
Nvm (optional)
Documentation:
Note: Optional, but nvm allows you to easily install and switch between node versions
VS Code (optional)
Highly recommend using a code editor like VS code.
Step 2: Clone the relayer-v2 repo:
If using VS code, open the terminal and run the following command:
Step 3: Run Redis
Open a terminal window and run:
Step 4: Environment Variables
Change the .env.example file to .env
In line 8 and 9, uncomment either the MNEMONIC or PRIVATE_KEY and input a private key that has no money on it.
I used to create a private key to use for the demo but again, do not use one that has any money on it as it is an unnecessary risk.
Step 5: Run the script
The below is an example, however the two changes that need to be made based on the request are:
REQUEST_TIME=CHANGE_THIS_TO_THE_TIMESTAMP
I used privateKey for the below, however, if you used mnemonic in your env variables, it should be changed to –wallet mnemonic
Note: The first time you run this, it is going to take a long time.
REQUEST_TIME=1692110627 ts-node ./src/scripts/validateRootBundle.ts --wallet privateKey
When the script finishes running, check the Validation results as shown below. The below shows an example of an invalid bundle as it shows “valid”: false:
Appendix
For additional documentation on Across root bundles, visit:
The next iteration of the UMA DVM
The UMA DVM is the arbitrator for the Optimistic Oracle and other UMA ecosystem contracts. It facilitates dispute resolution wherein UMA token holders vote in a commit reveal schelling point mechanism. For an overview of how the DVM see here. The DVM has been rebuilt with the new iteration being released in Q1 of 2023.
At a high level, the upgrade adds a new staking and slashing mechanism wherein voters earn a pro-rata share of emissions for staking and are slashed for voting wrong (or not voting). This upgrade also reworks a number of other DVM contracts such as the governor, proposer contract and a new designated voting contract. Finally, this upgrade adds a new emergency recovery mechanism to the DVM that enables admin proposals to bypass the DVM's schelling point oracle system in the event of an emergency. More detail on the individual changes are broken down in the sections that follow.
This doc page outlines some of the changes between DVM 1.0 and DVM 2.0 and some other relevant implementation details.
The DVM2.0 introduces three key changes to how the UMA token interacts with DVM system:
Voters now must stake UMA in the DVM to participate in the schelling point and to receive rewards.
Voters now earn a pro-rata share of a fixed emission rate simply for staking their tokens. Staking rewards are emitted at a constant rate per block. This means you can work out the overall UMA inflation over time and stakers can easily work out their APY for staking in the system. In comparison to the previous inflation system, the total inflation rate is no longer a factor of the number of votes held by the DVM. The pro-rata share of tokens received by stakers is independent of their voting performance. The emissions rate is set through UMA governance.
Voters' staked balances are also now susceptible to slashing. The slashing mechanism redistributes tokens from inactive and wrong voters to the stakers who voted correctly. This hardens the schelling point by adding a more punitive cost function to being wrong. Governance votes are treated as a special price request category where the slashing mechanism is not applied.
First class vote delegation support enabling a 1 to 1 relationship between the delegator and delegate wallets. This lets a voter delegate from a secure cold storage wallet to a hot wallet. The hot wallet can commit, reveal and claim and re-stake their rewards but cannot access the underlying stake. If desired, more complex delegation systems (pooled UMA staking with delegate voting etc) can be built on top of this externally to the core UMA contracts.
The DVM 2.0 now has an emergency recovery mechanism where bonded emergency proposals can be executed to short-circuiting and bypass the normal voting mechanism. This enables the DVM to recover from any kind of internal failure mode that could occur (breakage in the commit reveal system, contract issues or other) through a permissionless upgrade flow.
There are a number of other changes made, including:
Governance proposals now include ancillary data enabling better identifying information to be passed along to voters.
Price requests now contain a unique identifier, enabling easier tracking and support in front ends.
A number of gas optimizations were made throughout the protocol.
The sections below contain some details on nuanced implementation details of the DVM2.0 system.
Staking rewards (and the associated APY) consists of two discrete components: a) rewards from being staked and b) balance changes from slashing. The net staking APY you receive considers both of these values. Let's consider them separately.
Staking rewards are a pro-rata share of a fixed emission rate, calculated on a per block basis. The rewards you are entitled to, from the last time you claimed, are calculated as follows:
Slashing rewards & penalties at the time of DVM 2.0 launch are designed to be as simple as possible, with the ability to update them at a later point through the use of a Slashing Library. At launch, slashing penalties will be approximately equal to the rewards one would have earned for an estimated stake duration. This has been targeted based off historical DVM 1.0 vote frequency, and means that someone who stakes but does not participate in any votes (or gets all votes wrong) should have their slashed stake and accumulated rewards cancel out for a 0% APY. This amounts to losing 0.1% of your staked amount per vote that is incorrect or missed. Note that each voting round (48 hour commit-reveal cycle) can have multiple votes in it (for example multiple price requests or governance actions). The amount you earn for voting correctly is the voters pro-rata share of the slashing of the incorrect voters. This can be calculated per voter per round as follows:
Then, the total amount slashed per round is the sum of all voters slash for that round:
A voter, who was correct, will then earn a pro-rater share of the totalSlashPerRound as:
A staker's net APY is therefore the sum of their stakingRewards and positiveSlashForCorrectVotePerRound annualized over a 1 year period.
Under some situations votes can "roll". We define a rolled vote as a vote that was not resolved in one vote round and was moved into the subsequent voting round due to not successfully reaching the two types of needed quorums. These quorums are known as GAT (God Awful Threshold) and SPAT (Schelling Point Activation Threshold).
The GAT within the DVM 2.0 is a constant amount of UMA that must vote on any given vote for it to not roll. In the DVM 1.0, this was set as a percentage of circulating UMA. At the time of DVM 2.0 initial deployment, the required GAT per vote is a constant 5 million UMA.
The SPAT is a new concept from the DVM 2.0. It is a percentage of staked tokens that must vote and agree in order for a vote to not roll. The required SPAT is 65% currently of staked tokens.
If a vote does not satisfy both of these constraints, it will roll.
There are certain situations in the DVM 2.0 where voters may want to delete votes. A good example of this would be in the case of spam deletion, where needless price requests are submitted in order by an attacker to try to create some sort of desired slashing conditions.
In the DVM 2.0, votes are deleted once they have rolled a certain number of times. So if voters choose to not vote on the resolution of price requests, and either the GAT or SPAT are not met for a set number of voting rounds, those price requests will become deletable. At the time of DVM 2.0 initial deployment, the number of times a vote is rolled before being deleted is 4.

In the .env file, update the following env variables to the URL for your infura account. The underscore number at the end of the variable represents the chain ID. So RPC_PROVIDER_ALCHEMY_1 is mainnet.
You can use https://chainlist.org/ to find the ID by network.
Include the NODE_URL_324 for zksync below even though it hasn’t been added to the .env.example file yet:
{
financialContracts {
id
creator {
id
isRemoved
manager
}
deployer {
id
}
address
collateralToken {
id
name
}
collateralRequirement
expirationTimestamp
totalSyntheticTokensBurned
totalSyntheticTokensCreated
totalTokensOutstanding
cumulativeFeeMultiplier
globalCollateralizationRatio
rawTotalPositionCollateral
totalCollateralDeposited
totalCollateralWithdrawn
totalPositionCollateral
rawLiquidationCollateral
positions {
id
rawCollateral
collateral
tokensOutstanding
isEnded
}
liquidations {
id
status
amountWithdrawn
}
}
}git clone https://github.com/across-protocol/relayer-v2redis-server
From the README, run the three commands:
cd relayer-v2
yarn install
yarn buildRPC_PROVIDER_ALCHEMY_1=https://eth-mainnet.g.alchemy.com/v2/{API_KEY}
RPC_PROVIDER_ALCHEMY_10=https://opt-mainnet.g.alchemy.com/v2/{API_KEY}
RPC_PROVIDER_ALCHEMY_137=https://polygon-mainnet.g.alchemy.com/v2/{API_KEY}
RPC_PROVIDER_ALCHEMY_42161=https://arb-mainnet.g.alchemy.com/v2/{API_KEY}
NODE_URL_324=https://mainnet.era.zksync.io{
"at": "RootBundleValidator",
"message": "Validation results",
"rootBundle": {
"poolRebalanceRoot": "0x7005c47a8e476a2551d5325a6c53cd5b71f308b2ac670742ad7cceb8078a193f",
"relayerRefundRoot": "0x9edefc2fc000e71fa1ea1c6ce666a0f8cb2d6da422c45a372585da5e3b738713",
"slowRelayRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"proposer": "0xf7bAc63fc7CEaCf0589F25454Ecf5C2ce904997c",
"unclaimedPoolRebalanceLeafCount": 5,
"challengePeriodEndTimestamp": 1692117191,
"bundleEvaluationBlockNumbers": [
17920824,
108255396,
46338509,
977154,
121659934,
11305323
],
"proposalBlockNumber": 17920860
},
"valid": false,
"invalidReason": "Disputed pending root bundle:\n.....
// removed the rest of the invalidReason for the example{
liquidations {
id
status
sponsor {
id
}
liquidator {
id
}
disputer {
id
}
liquidationId
tokensLiquidated
lockedCollateral
liquidatedCollateral
disputeBondAmount
disputeSucceeded
amountWithdrawn
events {
__typename
}
}
}{
priceRequests {
id
isResolved
price
latestRound {
roundId
snapshotId
totalVotesRevealed
totalRewardsClaimed
totalSupplyAtSnapshot
votersAmount
votersClaimedAmount
tokenVoteParticipationRatio
tokenVoteParticipationPercentage
votersEligibleForRewardsRatio
votersEligibleForRewardsPercentage
votersClaimedRatio
votersClaimedPercentage
tokensClaimedRatio
tokensClaimedPercentage
winnerGroup {
votersAmount
totalVoteAmount
}
groups {
price
totalVoteAmount
won
votersAmount
}
}
time
identifier {
id
isSupported
}
committedVotes(first: 2) {
time
}
revealedVotes(first: 2) {
price
time
}
}
}Simple deposit box example that showcases the basic request propose lifecycle of the UMA Optimistic Oracle
UMA's Optimistic Oracle allows contracts to quickly request and receive price information. A request is made when a contract submits the following parameters with a request to the Optimistic Oracle contract:
identifier: price identifier being requested.
timestamp: timestamp of the price being requested.
ancillaryData: additional arguments passed with the price request.
currency: ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.
reward: reward offered to a successful proposer. Will be paid by the caller. Note: this can be 0.
Proposers respond to price requests by referencing off-chain price feeds to submit the price of an asset. In return for their work they will receive a pre-defined proposal reward set by the Requestor. To propose prices, the Proposer is required to stake a proposal bond. In the event that the price information they proposed is disputed and deemed incorrect, the Proposer will lose their bond.
Disputers can refute a price submitted by a Proposer within the proposal liveness period by referencing their own off-chain price feeds. The proposal liveness period is a pre-defined amount of time a proposal can be disputed before the Requestor receives the price of the asset.
If Disputers do not refute the price submitted by the Proposer within the proposal liveness period, the price is sent to the Requestor. If a proposal is disputed, the price will be submitted to UMA’s DVM and resolved after a 48-96 hour voting period.
We continue to use the contract as an example. The OptimisticDepositBox is a minimal financial contract that allows a user to deposit collateral into a contract and later withdraw their collateral corresponding to a desired USD amount. When the user wants to make a withdrawal, a price request is made to the Optimistic Oracle.
Let's first take a look at the OptimisticDepositBox constructor. Optimistic Oracle price requests require the use of a whitelisted identifier and collateral. The OptimisticDepositBox uses the protocol Finder to discover UMA protocol contracts and call the isOnWhitelist method on the AddressWhitelist and the isIdentifierSupported method on the IdentifierWhitelist contract to confirm both are whitelisted before deployment.
Example arguments used to deploy the contract can be found and tested in the . A whitelisted USDC contract is used for collateral, the Finder and Timer addresses use existing UMA ecosystem contracts that are deployed, and a price identifier that has been contract.
A price request is made when the requestWithdrawal is called. A depositor submits the denominatedCollateralAmount to withdrawal and a requestPrice call is constructed with the following arguments and in the :
After price request functionality has been implemented into your contracts, you can test your changes by creating a test in the developer quickstart repo similar to the OptimisticDepositBox test below:
The code snippets above represent the core functionality for deploying a minimal contract and requesting a price. The next step in the contract lifecycle after a request has been made is a price can be proposed.
is the proposePriceFor function from the Optimistic Oracle contract that is used to propose a price for requests. The price proposal will revert if the parameters do not match an existing price request. For reference, the demonstrates how to call the proposePriceFor method.
An important aspect to consider when using the Optimistic Oracle is the liveness period which is the number of seconds a proposal must wait before a price can be resolved and contracts can be settled. A defaultLiveness value is set (currently 7,200) or developers can set a customLiveness value.
To set a customLiveness value with our OptimisticDepositBox example above, we could add line 5 to change the liveness period from 7,200 seconds to 3,600:
A proposal bond is a preloaded reward to incentivize price proposals. Similar to the liveness period, a custom bond amount can be set for a price request.
Two important aspects to remember when setting a proposal bond is:
When making a price request, the caller must approve the contract to transfer the value of the proposer reward for the collateral being used.
The value corresponds to the collateral decimal value. So setting the reward to 1 for USDC that uses 6 decimals would be 1000000 while an 18 decimal token would be 1.
The below shows an example of setting the proposer bond to 50 USDC (6 decimals):
The OptimisticDepositBox contract uses the executeWithdrawal method to settle contracts. It first checks if a price has been resolved by calling the hasPrice method on the Optimistic Oracle which reverts if the request is not settled or settleable. If a price has been resolved, settleAndGetPrice is called.
Security of the platform is our highest priority. All contract code and balances are publicly verifiable, and security researchers are eligible for a bug bounty for reporting undiscovered vulnerabilities.
OpenZeppelin has performed the following audits on UMA contracts:
Additionally, OpenZeppelin audits incremental upgrades to UMA's contracts on a continuous basis. The continuous audit report can be found .
UMA encourages the community to audit our contracts and security; we also encourage the responsible disclosure of any issues. The bug bounty program is intended to recognize the value of working with the community of independent security researchers and sets out our definition of good faith in the context of finding and reporting vulnerabilities, as well as what you can expect from us in return.
UMA offers substantial rewards for discoveries that can prevent the loss of assets, the freezing of assets, or harm to users.
All rewards will be paid in $UMA, and the amount of compensation will vary depending on bug severity. Reward amounts typically correspond to severity in the following manner.
Severity is calculated according to the risk rating model based on Impact and Likelihood.
The scope of our bug bounty program includes any and all of UMA's production smart contracts. It does not include known issues with the intended behavior.
All UMA, Oval, or Across smart contracts that are deployed to mainnet or are otherwise noted as being applicable.
Bot or other offchain code to support deployed smart contracts.
Being able to steal funds
Being able to freeze funds or render them inaccessible by their owners
Issues that have already been submitted by another user or are already known to the UMA team
Note: this includes bugs known to the UMA team, but have not been disclosed due to active mitigation efforts.
Vulnerabilities in contracts built on top of the protocol by third-party developers (such as smart contract wallets)
Please email your submissions to .
The submission must include clear and concise steps to reproduce the discovered vulnerability.
If you comply with the policies below when reporting a security issue to us, we will not initiate a lawsuit or law enforcement investigation against you in response to your report.
We ask that you:
Report any vulnerability you’ve discovered promptly.
Avoid violating the privacy of others, disrupting our systems, destroying data, or harming user experience.
Use only to discuss vulnerabilities with us.
Keep the details of any discovered vulnerabilities confidential until they are publicly announced by Risk Labs.
Public disclosure of the bug or the indication of an intention to exploit it on Mainnet will make the report ineligible for a bounty. If in doubt about other aspects of the bounty, most of the will apply.
Any questions? Reach us via email (). For more information on the UMA platform, check out our and .
All reward determinations, including eligibility and payment amount, are made at UMA’s sole discretion. UMA reserves the right to reject submissions and alter the terms and conditions of this program without notice.
Any files, modules or libraries other than the ones mentioned above
More efficient gas solutions (although these suggestions are appreciated)
Any points listed as an already known weaknesses
Any points listed in an audit report
Perform testing only on in-scope systems, and respect systems and activities which are out-of-scope.
Not engage in blackmail, extortion, or any other unlawful conduct.
Not be a current or former UMA Foundation employee, vendor, contractor, or the employee of an UMA vendor or contractor.
Low
$250
Medium
$3,000
High
$10,000
Critical
up to $1,000,000

constructor(
address _collateralAddress,
address _finderAddress,
bytes32 _priceIdentifier,
address _timerAddress
) nonReentrant() Testable(_timerAddress) {
finder = FinderInterface(_finderAddress);
require(_getIdentifierWhitelist().isIdentifierSupported(_priceIdentifier), "Unsupported price identifier");
require(_getAddressWhitelist().isOnWhitelist(_collateralAddress), "Unsupported collateral type");
collateralCurrency = IERC20(_collateralAddress);
priceIdentifier = _priceIdentifier;
}
...
function _getIdentifierWhitelist() internal view returns (IdentifierWhitelistInterface) {
return IdentifierWhitelistInterface(finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist));
}
function _getAddressWhitelist() internal view returns (AddressWhitelist) {
return AddressWhitelist(finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist));
}// Deploy the OptimisticDepositBox contract.
const optimisticDepositBox = await (
await getContractFactory("OptimisticDepositBox", deployer)
).deploy(usdc.address, parentFixture.finder.address, identifier, parentFixture.timer.address);function requestWithdrawal(uint256 denominatedCollateralAmount)
public
noPendingWithdrawal(msg.sender)
nonReentrant
{
OptimisticDepositBoxData storage depositBoxData = depositBoxes[msg.sender];
require(denominatedCollateralAmount > 0, "Invalid collateral amount");
// Update the position data for the user.
depositBoxData.withdrawalRequestAmount = denominatedCollateralAmount;
depositBoxData.withdrawalRequestTimestamp = getCurrentTime();
emit RequestWithdrawal(msg.sender, denominatedCollateralAmount, depositBoxData.withdrawalRequestTimestamp);
// A price request is sent for the current timestamp.
_requestOraclePrice(depositBoxData.withdrawalRequestTimestamp);
}
.....
// Requests a price for `priceIdentifier` at `requestedTime` from the Optimistic Oracle.
function _requestOraclePrice(uint256 requestedTime) internal {
OptimisticOracleInterface oracle = _getOptimisticOracle();
// For other use cases, you may need ancillary data or a reward. Here, they are both zero.
oracle.requestPrice(priceIdentifier, requestedTime, "", IERC20(collateralCurrency), 0);
}await expect(optimisticeDepositBox.connect(depositor).requestWithdrawal(amountToWithdraw))
.to.emit(optimisticDepositBox, "RequestWithdrawal")
.withArgs(depositor.address, amountToWithdraw, requestTimestamp);request.expirationTime = getCurrentTime().add(
request.customLiveness != 0 ? request.customLiveness : defaultLiveness
);function _requestOraclePrice(uint256 requestedTime) internal {
OptimisticOracleInterface oracle = _getOptimisticOracle();
// For other use cases, you may need ancillary data or a reward. Here, they are both zero.
oracle.requestPrice(priceIdentifier, requestedTime, "", IERC20(collateralCurrency), 0);
oracle.setCustomLiveness(priceIdentifier, requestedTime, "", 3600);
}function _requestOraclePrice(uint256 requestedTime) internal {
OptimisticOracleInterface oracle = _getOptimisticOracle();
// For other use cases, you may need ancillary data. Here, the ancillary data is set to zero.
oracle.requestPrice(priceIdentifier, requestedTime, "", IERC20(collateralCurrency), 0);
oracle.setBond(priceIdentifier, requestedTime, "", 50000000);
}function _getOraclePrice(uint256 withdrawalRequestTimestamp) internal returns (uint256) {
OptimisticOracleInterface oracle = _getOptimisticOracle();
require(
oracle.hasPrice(address(this), priceIdentifier, withdrawalRequestTimestamp, ""),
"Unresolved oracle price"
);
int256 oraclePrice = oracle.settleAndGetPrice(priceIdentifier, withdrawalRequestTimestamp, "");
// For simplicity we don't want to deal with negative prices.
if (oraclePrice < 0) {
oraclePrice = 0;
}
return uint256(oraclePrice);
}General questions about UMA OO
Only required for testing the dispute flow
Whenever the assertion is disputed on a production network this triggers DVM request to be resolved by UMA voters. This might be impractical to fully simulate this in a testing environment, hence, developers can use mocked oracle contract to resolve requests as they had been returned by DVM.
Interacting with Optimistic Oracle requires having whitelisted price identifier and bonding currency. In production networks these are approved by UMA token holders as part of governance voting. When testing, it might be easier for developers to use their own set of UMA ecosystem contracts where they have full control over such whitelisting process. Follow the written tutorial below or check out the video tutorial on Youtube.
A set of sandboxed UMA ecosystem contracts can be deployed using forge script from .
After cloning the repository make sure you have the latest Foundry version by running foundryup command (see more installation details on ). From the root of the repository install dependencies with:
All script parameters are controlled through environment variables that should be exported before running the script:
ETH_RPC_URL: URL of the RPC node to use for broadcasting deployment transactions on the desired test network.
MNEMONIC: Mnemonic of the account to use for deployment (derived account with 0 index will be used by default).
ETHERSCAN_API_KEY: API key for Etherscan, used for verifying deployed contracts.
Once all required environment variables are setup, deploy and verify the set of sandboxed UMA ecosystem contracts with:
At the top of the script output the addresses of the deployed contracts should be logged:
Finder: Used to locate other UMA ecosystem contract addresses. Deployment script will have added new Store, AddressWhitelist, IdentifierWhitelist, MockOracleAncillary and OptimisticOracleV3 implementations.
Store: Stores final fees of bonding currencies. The script will have set the final fee of default currency to half of provided minimum bond amount since Optimistic Oracle V3 calculates minimum bond twice the value of this final fee.
Whenever the assertion is disputed, Optimistic Oracle V3 calls requestPrice method on the Oracle that triggers DVM vote on mainnet. In the sandboxed environment this would resolve to MockOracleAncillary contract instead.
The disputed request is uniquely identified by its identifier, timestamp and ancillary data that should be referenced by the testing developer pushing resolved price to the mocked oracle. The MockOracleAncillary contract will emit PriceRequestAdded event with following parameters:
address indexed requester: Address of the calling contract (Optimistic Oracle V3 in the sandboxed setup).
bytes32 indexed identifier: Identifier referencing the rules on how the request should be resolved. By default Optimistic Oracle V3 uses ASSERT_TRUTH identifier unless the integrating contract provided other value.
uint256 time
Note that production voting contract on mainnet emits this differently and above PriceRequestAdded is provided only as a convenience for developers when interacting with the MockOracleAncillary contract in their testing environment.
MockOracleAncillary contract provides two alternative methods for testing developers to resolve request:
pushPrice(bytes32 identifier, uint256 time, bytes memory ancillaryData, int256 price) where request is referenced by its individual parameters.
pushPriceByRequestId(bytes32 requestId, int256 price) where request is referenced by the hashed value of its identifying parameters.
While testing developer can pass any int256 price value, Optimistic Oracle V3 can only interpret value of 1e18 to represent truthful assertion. Any other value would settle assertion as being false. Also note that MockOracleAncillary contract will only accept the first pushed price to resolve a given request.
As an illustration to the section above this example walks through resolving disputed assertion with cast tool from Foundry. This also requires jq being installed for parsing returned values.
Just for the sake of simplicity set MINIMUM_BOND environment variable to 0 when running forge script command as discussed in the . This would allow to skip minting and approving assertion/dispute bonds. Take a note of deployed contracts log and export Optimistic Oracle V3 address to OOV3_ADDRESS and MockOracleAncillary address to MOCK_ORACLE_ADDRESS environment variables.
Also to keep this simple perform all steps from the same address:
Start with generating test assertion and grab the resulting assertionId emitted by Optimistic Oracle V3 (corresponds to topic index 1 in the AssertionMade event):
Dispute the above assertion and grab the resulting requestId emitted by MockOracleAncillary (corresponds to topic index 3 in the PriceRequestAdded event):
Now resolve the disputed assertion as truthful by pushing 1e18 as price to MockOracleAncillary contract:
This allows us to settle the assertion at Optimistic Oracle V3:
Finally, you can verify that Optimistic Oracle V3 has correctly settled the assertion (this should return true):
The deployment script documented in the covers most common use cases and should be sufficient to test example contracts from the . Though, when developing your own integrating contracts it might be required to further configure the sandboxed oracle environment.
In case the integrating contract requires handling assertion bonds in multiple currencies all of them should be approved at the AddressWhitelist contract. On production this should go through UMA governance while in the sandboxed environment the deployer owns this contract and can call addToWhitelist method directly. Assuming the address of AddressWhitelist contract is exported to ADDRESS_WHITELIST and required bonding currency is exported to BONDING_CURRENCY environment variables, this can be done by:
In order to test the scenario on how the integrating contracts would behave if UMA governance removed support for a particular bonding currency, you can test this by calling removeFromWhitelist method on the AddressWhitelist contract:
Note that Optimistic Oracle V3 is caching whitelisted bonding currencies. Hence, before testing impact on the integrating contracts somebody should sync the contract cache (anyone has authority to do this):
In case the UMA governance was to change the configured final fee for a particular bonding currency this would also change the minimum assertion bond required by Optimistic Oracle V3. In order to test such impact on integrating contracts in the testing environment, the deployer would need to call setFinalFee on the Store contract (exported as STORE_ADDRESS). E.g. to set final fee to 1000e18, you would call:
Again, before testing impact on integrating contracts someone would need to sync new final fee at the Optimistic Oracle V3:
If the integrating contract plans to make assertions with multiple identifiers, the developer would need to add them to IdentifierWhitelist contract (exported as IDENTIFIER_ADDRESS) in the sandboxed environment, e.g. adding CUSTOM_IDENTIFIER:
In order to test the scenario on how the integrating contracts would behave if UMA governance removed support for a particular identifier, you can test this by calling removeSupportedIdentifier method on the IdentifierWhitelist contract:
Note that Optimistic Oracle V3 is caching whitelisted identifiers. Hence, before testing impact on the integrating contracts somebody should sync the contract cache (anyone has authority to do this):
How to verify oSnap Proposals
oSnap uses the ASSERT_TRUTH identifier can be found here. ASSERT_TRUTH is intended to be used as a default price identifier for UMA's Optimistic Oracle V3 contract that allows asserters to make claims about the state of the world.
Price settlement can happen only in one of two ways:
Return the 1 value if the claim is true.
Return the 0 value if the claim is false or cannot be resolved.
Part 1: Snapshot Proposal Created
When a Snapshot proposal is created, a Discord ticket is created with a Tenderly simulation of the transaction payload. Here is an example:
The main objective of verifying the Snapshot proposal before voting is to ensure:
The transaction payload can be executed
Comparing the intent of the proposal against the transaction payload
The transaction payload doesn't have any unintended consequences or malicious intent
In the Tenderly simulation, if the Status value is not Success, that is an indicator the transaction payload is unable to be executed and requires further review.
The input shows the transactions array that will be executed if the Snapshot proposal passes:
Verifying the transaction data
Go to .
Input the contract ABI into the ABI section
Take the ‘to’ value from the transaction object and input it into etherscan (or the block explorer based on the chainID. For etherscan, you would go to }.
Here is what the example would look like:
The ‘Output’ for a Transfer should look as the below:
Verify the following:
For any BigNumber values, go to and input BigNumber.from("{INPUT_VALUE}").toString(). For example, BigNumber.from("0x14adf4b7320334b9000000").toString() would be 25000000000000000000000000. To scale this value, go to the token contract address and check decimals. For the ACX token, the decimals are 18 so the scaled value is 25000000. You can use if the decimals are 18.
Confirm that the above value is mentioned in the actual Snapshot proposal.
Part 2: oSnap Transactions Proposed
After a Snapshot proposal is completed, if the proposal is valid the transactions are proposed which creates another Discord ticket. is an example thread in the UMA Discord.
The first objective is to verify the oSnap rules against Snapshot Proposal. Click the Snapshot space URL, in the above example that is . Go through the list of proposals and confirm the explanation from the Discord message matches the Snapshot space.
Validators should do the following to verify the oSnap proposal:
Check the Snapshot space referenced in the rules string.
Check that the IPFS hash passed as the explanation lines up with an actual vote in that Snapshot space. They should be able to cross-reference the value with a link from a specific Snapshot proposal.
Check the Snapshot proposal tied to the IPFS explanation value met the minimum voting period and quorum.
Compare Snapshot IPFS Transaction data against Proposed Transactions
Go to the Snapshot proposal and click the ‘View Details’ link in the Transactions container:
Copy the “transactions” array into . You should use Firefox or Brave so that backslashes “\” aren’t included in the array which will give you an error message when trying to parse:
3. In the Discord post, click the transaction:’
Then copy the ‘Transaction Hash’:
Go to and paste the ‘Transaction Hash’. Then click ‘Show’ to check the input data.
In the Discord Ticket, paste the screenshots of Tenderly and json formatter and also paste the transaction data into another thread message as below:
The following should be verified:
‘data’ from Tenderly matches the transaction data from Snapshot.
‘value’ from Tenderly matches the transaction data from Snapshot.
‘to’ from Tenderly matches the transaction data from Snapshot.
Verify the explanation:
Building a prediction market that uses the UMA Optimistic Oracle for settlement and event identification
In this section, we'll talk about the , which you can find in the . This tutorial will show how event-based OO data requests can be used in a binary prediction market.
You will find out how this smart contract works and how to test it and deploy it. Refer to the contract for additional information on the event-based price requests.
This smart contract lets you set up prediction markets that are based on an event-based price request.
The following are the evaluation criteria UMA considers when adding Optimistic Oracle support for a new network. UMA aims to support as many networks as possible to deliver the best experience for our integrating protocols and users. However, integrating a new network requires a significant investment. Therefore, the evaluation criteria were established to ensure that the benefits to UMA's integrating protocols and users outweigh the development, security, and operational costs of adding a new network.
Please note that these requirements are subject to change as the EVM (Ethereum Virtual Machine) and Layer 2 ecosystem continue to evolve. Meeting these requirements is the initial step in our evaluation process and does not guarantee support.
The below are a pre-requisite to any consideration:
EVM-Compatible Network a canonical token and message bridge to mainnet
≥ 2 or more Independent RPC Node Providers (without block range limits for log queries)
30-Day Moving Average TVL on the network > $75M
Block Explorer with Etherscan-Compatible API, contract verification and ABI fetching
Availability of token mappings data source with Ethereum mainnet
Dedicated support channel containing technical members of the network with priority support commitment to advise on contract development and debug data quality
Subgraph support for testnet and mainnet
Wallet connector libraries support for testnet and mainnet
Drop a message in the UMA Discord Server
Send an email to [email protected]
DEFAULT_IDENTIFIER: Default identifier used by Optimistic Oracle V3 when resolving disputes. If not provided, this defaults to ASSERT_TRUTH identifier. The script will also whitelist this identifier.
DEFAULT_LIVENESS: Default liveness in seconds used by Optimistic Oracle V3 when settling assertions. If not provided, this defaults to 7200 seconds.
DEFAULT_CURRENCY: Default currency used by Optimistic Oracle V3 when bonding assertions and disputes. The script will also whitelist this currency. If not provided, the script would also deploy a mintable ERC20 token and use it as the default currency based on following parameters:
DEFAULT_CURRENCY_NAME: Name of the new token. If not provided, this defaults to Default Bond Token.
DEFAULT_CURRENCY_SYMBOL: Symbol of the new token. If not provided, this defaults to DBT.
DEFAULT_CURRENCY_DECIMALS: Number of decimals of the new token. If not provided, this defaults to 18.
MINIMUM_BOND: Minimum bond amount in Wei of default currency required by Optimistic Oracle V3 when accepting new assertions. If not provided, this defaults to 100e18 Wei.
AddressWhitelist: Stores approved currency addresses that can be used for bonding assertions and disputes. The script will have already whitelisted the default currency.
IdentifierWhitelist: Stores approved identifiers that can be used to resolve disputes at DVM. The script will have already whitelisted the default identifier.
MockOracleAncillary: Optimistic Oracle will use this contract to resolve disputes equivalent to DVM voting on mainnet. Once requested, anyone can push desired test price through this mock oracle contract.
TestnetERC20: Unless existing default currency was provided the script will have deployed this new token that is whitelisted as a bonding currency. Anyone can mint new tokens by calling its allocateTo(address ownerAddress, uint256 value) method.
OptimisticOracleV3: Optimistic Oracle that resolves assertions made by integrating contracts.
bytes ancillaryData: Optimistic Oracle V3 will put the assertionId and address of the asserter referencing the disputed assertion.
bytes32 indexed requestId: This is hashed value of identifier, time and ancillary data provided by the MockOracleAncillary contract just as convenient method to resolve request by one parameter instead of three separate parameters.
(Note: Although these are called "price" requests in the code, you can request any kind of data from the optimistic oracle. If it's helpful, you can mentally replace "price" with "data" when you see it in the code and documentation.)
In addition, an event-based price request cannot expire early and automatically returns the requester's reward in the event of a dispute. By participating in the contract, users are issued long and short position tokens, which, when held, provide exposure to the prediction market. This contract's logic is a streamlined version of the LongShortPair with an event-based pricing request.
To install dependencies, you will need to install the long-term support version of nodejs, currently nodejs v16, and yarn. You can then install dependencies by running yarn with no arguments:
We will need to run the following command to compile the contracts and make the typescript interfaces so that they are easy to work with:
The contract is created by setting up the prediction market with a series of parameters. With the parameters, you can choose what kind of collateral you want to use with _collateralToken. With _pairName, we can choose a name for the pair of long and short tokens. _customAncillaryData is where we define the price request question. The addresses of the _finder and _timerAddress set the rest of the contracts addresses we interact with. For reference, here is the full list of UMA contract deployments.
Once the contract has been deployed, the owner can call initializeMarket() after approving the proposerReward amount to be paid to the wallet that resolves the price request. To keep things simple, proposerReward is set to 10e18.
Also observe how priceIdentifier is set to "YES_OR_NO_QUERY".
This function sets up the prediction market by getting the proposer reward and calling _requestOraclePrice. This last function starts the price request in Optimistic Oracle V2 and sets up a number of options that are explained below.
_requestOraclePrice is in charge of initializing the price request in the Optimistic Oracle V2 by performing the following actions:
Create the price request with the above-mentioned parameters.
Define the custom liveness period that a proposed oracle response must sit through before being accepted as truth.
Specify the bond that the proposer and disputer must post in order to resolve a request.
Set the type of request to Event Based.
Turn on the priceSettled and priceDisputed callbacks so that our contract can use OO callbacks to respond to these kinds of events
Any user can now call the create function with the tokensToCreate parameter to mint the same number of short and long tokens. Having both tokens in the same proportion means being in a neutral position, as is the case when calling create.
Holding only long tokens (by transferring short tokens to another wallet or adding liquidity to an AMM pair), gives exposure to the long position and vice versa.
At any time a token holder with both tokens in the same proportion can exchange them for collateral with `redeem`.
Any long-short token holder can settle tokens for collateral with settle if the oracle has processed the price request.
The returned collateral amount is a function of longTokensToRedeem, shortTokensToRedeem, and settlementPrice.
When the price request we set up above is settled in the Optimistic Oracle V2, the priceSettled function of this contract is invoked.
This function calculates and stores settlementPrice as 0, 0.5, or 1. This number is used in the settle function to calculate the collateral to pay in exchange for long tokens and short tokens.
In the same way, this contract's priceDisputed function is called when a price request is disputed. This function re-starts the same price request with the bond amount that was given back to the requester, which in our case is the EventBasedPredictionMarket.
To execute the EventBasedPredictionMarket tests, run:
Before deploying the contract check/edit the default arguments defined in the deployment script.
To deploy EventBasedPredictionMarket in Görli network, run:
Optionally, you can verify the deployed contract on Etherscan:
forge installforge script \
--broadcast \
--fork-url $ETH_RPC_URL \
--mnemonics "$MNEMONIC" \
--sender $(cast wallet address --mnemonic "$MNEMONIC") \
--verify \
script/OracleSandbox.s.solexport USER_ADDRESS=$(cast wallet address --mnemonic "$MNEMONIC")export ASSERTION_TX=$(cast send --mnemonic "$MNEMONIC" --json $OOV3_ADDRESS "assertTruthWithDefaults(bytes,address)" $(cast --from-utf8 "test claim") $USER_ADDRESS | jq -r '.transactionHash')
export ASSERTION_ID=$(cast receipt --json $ASSERTION_TX | jq -r --arg OOV3_LOWERCASE $(echo $OOV3_ADDRESS | tr [:upper:] [:lower:]) '.logs[] | select(.address==$OOV3_LOWERCASE).topics[1]')export DISPUTE_TX=$(cast send --mnemonic "$MNEMONIC" --json $OOV3_ADDRESS "disputeAssertion(bytes32,address)" $ASSERTION_ID $USER_ADDRESS | jq -r '.transactionHash')
export REQUEST_ID=$(cast receipt --json $DISPUTE_TX | jq -r --arg MOCK_LOWERCASE $(echo $MOCK_ORACLE_ADDRESS | tr [:upper:] [:lower:]) '.logs[] | select(.address==$MOCK_LOWERCASE).topics[3]')cast send --mnemonic "$MNEMONIC" $MOCK_ORACLE_ADDRESS "pushPriceByRequestId(bytes32,int256)" $REQUEST_ID $(cast --to-wei 1)cast send --mnemonic "$MNEMONIC" $OOV3_ADDRESS "settleAssertion(bytes32)" $ASSERTION_IDcast call $OOV3_ADDRESS "getAssertionResult(bytes32)(bool)" $ASSERTION_IDcast send --mnemonic "$MNEMONIC" $ADDRESS_WHITELIST "addToWhitelist(address)" $BONDING_CURRENCYcast send --mnemonic "$MNEMONIC" $ADDRESS_WHITELIST "removeFromWhitelist(address)" $BONDING_CURRENCYcast send --mnemonic "$MNEMONIC" $OOV3_ADDRESS "syncUmaParams(bytes32,address)" $(cast --format-bytes32-string "") $BONDING_CURRENCYcast send --mnemonic "$MNEMONIC" $STORE_ADDRESS "setFinalFee(address,(uint256))" $BONDING_CURRENCY "($(cast --to-wei 1000))"cast send --mnemonic "$MNEMONIC" $OOV3_ADDRESS "syncUmaParams(bytes32,address)" $(cast --format-bytes32-string "") $BONDING_CURRENCYcast send --mnemonic "$MNEMONIC" $IDENTIFIER_ADDRESS "addSupportedIdentifier(bytes32)" $(cast --format-bytes32-string "CUSTOM_IDENTIFIER")cast send --mnemonic "$MNEMONIC" $IDENTIFIER_ADDRESS "removeSupportedIdentifier(bytes32)" $(cast --format-bytes32-string "CUSTOM_IDENTIFIER")cast send --mnemonic "$MNEMONIC" $OOV3_ADDRESS "syncUmaParams(bytes32,address)" $(cast --format-bytes32-string "CUSTOM_IDENTIFIER") 0x0000000000000000000000000000000000000000git clone [email protected]:UMAprotocol/dev-quickstart.git
cd dev-quickstartyarnyarn hardhat compile constructor(
string memory _pairName,
ExpandedERC20 _collateralToken,
bytes memory _customAncillaryData,
FinderInterface _finder,
address _timerAddress
) ...function _requestOraclePrice() internal {
OptimisticOracleV2Interface optimisticOracle = getOptimisticOracle();
collateralToken.safeApprove(address(optimisticOracle), proposerReward);
optimisticOracle.requestPrice(
priceIdentifier,
requestTimestamp,
customAncillaryData,
collateralToken,
proposerReward
);
// Set the Optimistic oracle liveness for the price request.
optimisticOracle.setCustomLiveness(
priceIdentifier,
requestTimestamp,
customAncillaryData,
optimisticOracleLivenessTime
);
// Set the Optimistic oracle proposer bond for the price request.
optimisticOracle.setBond(priceIdentifier, requestTimestamp, customAncillaryData, optimisticOracleProposerBond);
// Make the request an event-based request.
optimisticOracle.setEventBased(priceIdentifier, requestTimestamp, customAncillaryData);
// Enable the priceDisputed and priceSettled callback
optimisticOracle.setCallbacks(priceIdentifier, requestTimestamp, customAncillaryData, false, true, true);
priceRequested = true;
} function create(uint256 tokensToCreate) public requestInitialized {
collateralToken.safeTransferFrom(msg.sender, address(this), tokensToCreate);
require(longToken.mint(msg.sender, tokensToCreate));
require(shortToken.mint(msg.sender, tokensToCreate));
emit TokensCreated(msg.sender, tokensToCreate, tokensToCreate);
} function redeem(uint256 tokensToRedeem) public {
require(longToken.burnFrom(msg.sender, tokensToRedeem));
require(shortToken.burnFrom(msg.sender, tokensToRedeem));
collateralToken.safeTransfer(msg.sender, tokensToRedeem);
emit TokensRedeemed(msg.sender, tokensToRedeem, tokensToRedeem);
} function settle(uint256 longTokensToRedeem, uint256 shortTokensToRedeem)
public
returns (uint256 collateralReturned)
{
require(receivedSettlementPrice, "price not yet resolved");
require(longToken.burnFrom(msg.sender, longTokensToRedeem));
require(shortToken.burnFrom(msg.sender, shortTokensToRedeem));
// settlementPrice is a number between 0 and 1e18. 0 means all collateral goes to short tokens and 1e18 means
// all collateral goes to the long token. Total collateral returned is the sum of payouts.
uint256 longCollateralRedeemed = (longTokensToRedeem * settlementPrice) / (1e18);
uint256 shortCollateralRedeemed = (shortTokensToRedeem * (1e18 - settlementPrice)) / (1e18);
collateralReturned = longCollateralRedeemed + shortCollateralRedeemed;
collateralToken.safeTransfer(msg.sender, collateralReturned);
emit PositionSettled(msg.sender, collateralReturned, longTokensToRedeem, shortTokensToRedeem);
}function priceSettled(
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData,
int256 price
) external {
OptimisticOracleV2Interface optimisticOracle = getOptimisticOracle();
require(msg.sender == address(optimisticOracle), "not authorized");
require(identifier == priceIdentifier, "same identifier");
require(keccak256(ancillaryData) == keccak256(customAncillaryData), "same ancillary data");
// We only want to process the price if it is for the current price request.
if (timestamp != requestTimestamp) return;
// Calculate the value of settlementPrice using either 0, 0.5e18, or 1e18 as the expiryPrice.
if (price >= 1e18) {
settlementPrice = 1e18;
} else if (price == 5e17) {
settlementPrice = 5e17;
} else {
settlementPrice = 0;
}
receivedSettlementPrice = true;
}function priceDisputed(
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData,
uint256 refund
) external {
OptimisticOracleV2Interface optimisticOracle = getOptimisticOracle();
require(msg.sender == address(optimisticOracle), "not authorized");
requestTimestamp = getCurrentTime();
require(timestamp <= requestTimestamp, "different timestamps");
require(identifier == priceIdentifier, "same identifier");
require(keccak256(ancillaryData) == keccak256(customAncillaryData), "same ancillary data");
require(refund == proposerReward, "same proposerReward amount");
_requestOraclePrice();
}yarn test test/EventBasedPredictionMarket/*NODE_URL_5=YOUR_GOERLI_NODE MNEMONIC=YOUR_MNEMONIC yarn hardhat deploy --network goerli --tags EventBasedPredictionMarketETHERSCAN_API_KEY=YOUR_API_KEY yarn hardhat etherscan-verify --network goerli --license AGPL-3.0 --force-license --solc-inputResolve: Rewards and slashing is based on voting accuracy.
Votes are shielded, meaning that voters cannot see each other's votes until after the reveal phase starts.
Optimism Mainnet
Arbitrum Mainnet
Base Mainnet
Blast Mainnet
Core Mainnet
Story Mainnet
For the most up-to-date list of supported networks, including testnets and partially supported chains, you can find UMA's network information here.
Settle multiple events faster and more efficiently.
Use cases like Polymarket and sports betting platforms directly benefit from this added scale and flexibility.
Makes oracle usage more cost-effective in congested markets.
This is especially helpful for integrations that involve complex or large datasets.
Truthful participation is rewarded.
Dishonesty is costly.
Corruption is uneconomical.
That’s how UMA turns incentive design into a security system at scale.
Voters stake $UMA, which can be slashed if they vote inaccurately or are absent for voting rounds. On the other hand, they earn staking rewards for participating and voting accurately.
$UMA stakers participate in securing the DVM by voting on oracle resolutions. While small slashing and reward mechanisms exist (~0.1% of stake), the real security comes from the economic incentive to protect the system. If the DVM were corrupted, UMA’s value would likely collapse, meaning attackers would lose far more than they could gain.
This economic structure creates a financial deterrent against dishonest behavior. The system is built in such a way where honesty is profitable and lying is expensive.
SPAT (Schelling Point Activation Threshold) is a new rule in DVM 2.0. It requires at least 65% of staked $UMA to vote and agree on the same outcome.
If either threshold isn’t met, the vote rolls into the next round. It's designed this way to make sure there's both broad participation and meaningful agreement before a dispute is finalized.
Bond size: Increase the required stake for proposers or disputers to raise the cost of dishonest participation.
Resolution criteria: Add detailed instructions or requirements to help voters resolve disputes clearly and accurately.
Data format: You define the format of the data to be verified (e.g. booleans, multiple-choice, integers, or encoded data using upgrades like UMIP-185).
Optimism Sepolia
Polygon Mumbai
Polygon Amoy
Base Sepolia
Blast Sepolia
Core Testnet
Story Odyssey
You can view the full list of supported chains here.
IP dispute verification (e.g. Story Protocol)
AI agent verification (e.g. Axal)
Insurance protocol
Technical feasibility
Ecosystem impact
Budget/funding needs
Have questions? Come chat with us in Discord.
UMA Snapshot Space – Where tokenholders vote on proposals.
UMA Docs – Developer documentation, guides, and protocol deep dives.
UMA Blog – Insights, announcements, and ecosystem updates.







Scroll down to the ‘Contract ABI’ section and copy everything
Paste it into the ABI section
Search for the token in coingecko.com with the token address and confirm there is liquidity.
Go to https://playground.ethers.org/ and input the following explanation to ethers.utils.toUtf8String(“{explanation}”).toString()
Take the returned value and input it into the following url ‘https://snapshot.4everland.link/ipfs/{explanation} and verify that the data matches from Snapshot


Risk Labs operates monitoring bots for the following networks and integrations for additional resiliency.
The following networks are supported, but Risk Labs does not provide additional monitoring
{
"method": "transfer",
"types": [
"address",
"uint256"
],
"inputs": [
"9040e41eF5E8b281535a96D9a48aCb8cfaBD9a48",
{
"type": "BigNumber",
"hex": "0x14adf4b7320334b9000000"
}
],
"names": [
"to",
"amount"
]
}Tenderly:
[
{
"to": "0x44108f0223a3c3028f5fe7aec7f9bb2e66bef82f",
"operation": 0,
"value": "0",
"data": "0xa9059cbb0000000000000000000000009040e41ef5e8b281535a96d9a48acb8cfabd9a4800000000000000000000000000000000000000000014adf4b7320334b9000000"
}
]
Snapshot IPFS:
[
{
"operation": "0",
"data": "0xa9059cbb0000000000000000000000009040e41ef5e8b281535a96d9a48acb8cfabd9a4800000000000000000000000000000000000000000014adf4b7320334b9000000",
"to": "0x44108f0223A3C3028F5Fe7AEC7f9bb2E66beF82F",
"value": "0"
}
]137
Yes
Yes
(testnet)
80002
Yes
No
10
Yes
Yes
42161
Yes
Yes
8453
Yes
Yes
(testnet)
84532
Yes
No
No
81457
Yes
Yes
(testnet)
168587773
Yes
No
No
1514
Multi-sig relay
Yes
43114
Multi-sig relay
Yes
No
No
(Deprecated)
1116
n/a
No
No
((testnet)(deprecated)
42
n/a
No
No
(testnet)(deprecated)
4
n/a
No
No
((testnet)(deprecated)
5
Yes
No
No
(testnet)(deprecated)
80001
Yes
No
(testnet)(deprecated)
421611
Yes
No
No
(Deprecated)
100
n/a
No
No
Ethereum Mainnet (Across only)
1
Yes
Yes
Polygon Mainnet (Polymarket only)
137
Yes
Yes
1
Yes
Yes
Ethereum Sepolia (testnet)
11155111
Yes
Story Odyssey (testnet)(deprecated)
1516
Yes
No
Boba Mainnet (Deprecated)
288
n/a
No
No

Using the Optimistic Oracle V3 to assert arbitrary off-chain data on-chain.
This section covers the Data Asserter contract, which is available in the Optimistic Oracle V3 quick-start repo. This tutorial shows an example of how to build an arbitrary data asserter contract, using the UMA Optimistic Oracle V3 (OOV3) contract. This enables you to assert to the correctness of some off-chain process and store the output on-chain. This tutorial acts as a starting point to show how the OOV3 can be flexibility used in a sample integration.
This smart contract allows data providers to assert the correctness of a data point, within any arbitrary data set, and bring the result on-chain. This contract is designed to be maximally open ended, enabling any kind of data to be asserted. For example, and for illustrative purposes of this tutorial, we will assert weather data on-chain. Note, though, that this kind of assertion flow and the associated OOV3 integration could build a wide range of assertions with arbitrary complexity. For example you could use the same structure to bring on-chain complex data associated with Beacon chain validator set to build a Liquid staking derivative, enable complex off-chain computation with on-chain outputs or anything that has a defined deterministic input output relationship.
Anyone can assert a data point against the Data Asserter contract, with a known dataId and datapoint. Independent 3rd parties can then verify the correctness of this data against the dataId.
For our example we will be asserting the output of a very simple numerical computation: 69+420. This is meant to show the basic idea without overcomplicating the off-chain part. Note, though, that the dataId prop used here could represent any kind of unique data identifier (a row in a database table, a validator address or a complex structure used to associate any kind of data to a given value.
This project uses as the Ethereum testing framework. You will also need to install Foundry, refer to if you don’t have it already.
You will also need git for cloning the repository, as well as bash shell and jq tool in order to parse transaction outputs when interacting with deployed contracts.
Clone the UMA and install the dependencies:
The contract discussed in this tutorial can be found at dev-quickstart-oov3/src/DataAsserter.sol () within the repo.
To initialize the state variables of the contract, the constructor takes two parameters:
_defaultCurrency parameter in the constructor identifies the token used for bonds of data assertions. This token should be approved as whitelisted UMA collateral. Please check for production networks or call getWhitelist() on the contract for any of the test networks. Note that the deployed Optimistic Oracle V3 instance already has its defaultCurrency added to the whitelist, so it can also be used by the Data Asserter contract. Alternatively, you can approve a new token address with addToWhitelist method in the Address Whitelist contract if working in a sandboxed UMA environment.
_optimisticOracleV3
assertDataFor method allows any data provider to assert some value of data for the associated dataId. The caller sets the asserter as the address that will receive bonds at resolution of the data assertion (this could be their address as well).
Internally, this function pulls the associated assertion bond (global for all assertions within the DataAssertion contract) from the caller, makes an assertion call to the Optimistic Oracle V3 and stores the assertion within the contracts internal assertionsData mapping. Lastly, an event is emitted.
For the context of this example we will be considering the dataId simply as the URL that would be called to fetch the weather data from wttr.in and the data value as the result from this call. Both are bytes32 encoded.
The call to the Optimistic Oracle V3 looks as follows:
Lets break this down step by step:
First, the value for the claim filed is constructed to be a human readable string as the concatenation of a number of different data points. This is meant to be parsable by the validation network and enable both Humans and software verifiers alike to assess the correctness of the claim. Note that within the Optimistic Oracle V3 the claim field (this prop in this function call) is not stored on-chain; it is simply emitted and is used by off-chain actors to verify the correctness of the claim.
Next, the asserter field is passed in from this function call. This is who will receive the bonds back at resolution of the assertion, assuming the asserter was correct.
Once data has been asserted, the act of verifying it is passed over to the Optimistic Oracle V3 and the associated network of data verifiers. Due to the presence of a bond (reward for catching invalid assertions), we can be confident that in real world someone would verify this assertion (if the bond is high enough, and the liveness is long enough we have high guarantees of this).
If the assertion passes the assertionLiveness without dispute then it can be settled. The data assertion contract showcases the OOV3's concept of assertionResolvedCallback which enables the OOV3 to settle downstream contracts that are dependent on the resolution of an assertion. Once an assertion is settleable (it has: a) passed liveness and b) not been disputed) anyone can call on the OOV3. This function acts to settle the assertion within the OO and call into the callback recipient, set during the assertDataFor function call.
Looking within the Data Asserter contract, we can see what happens when the assertionResolvedCallback is hit from the OOV3 on settlement:
This function effectively:
enforce the inbound caller is the OOV3. Else, revert
If the assertion was resolved as truthful (it would not be if it was disputed and the dispute proved to be correct) then:
set the data assertion status to true,
Once settled, we can now call the getData function with the assertionId.This will return the data value and the accompanying resolution status (was it resolved truthfully, or not).
If we want to dispute an asserted data point one must simply call the method on the OOV3. In here, you provide the associated assertionId (the same field that was returned when calling assertDataand the disputer address (the address that will receive the bonds back at the resolution of the dispute).
All the unit tests covering the functionality described above are available . To execute all of them, run:
Before deploying and interacting with the contracts export the required environment variables. Note that there are a number of ways to interact with these contracts. The simplest setup is to fork Goerli testnet into a local development environment, using Anvil, and run the steps against the fork. To create an Anvil fork run the following:
Replacing xxx with your infura key. This will create a local fork of the Goerli testnet, running on 127.0.0.1:8545. It will also expose a test mnemonic that you can use which has pre-loaded Eth within the fork.
(Note: to set environment variables, as those listed below, use the export syntax in your shell. for example export ETH_RPC_URL=XXX
ETHERSCAN_API_KEY: your secret API key used for contract verification on Etherscan if deploying on a public network (not required if you want to do this against a local testnet).
ETH_RPC_URL: your RPC node used to interact with the selected network. For this tutorial it will be easiest to do this against the Goerli fork by setting ETH_RPC_URL=http://127.0.0.1:8545
MNEMONIC
Use cast command from Foundry to locate the address of Optimistic Oracle V3 and its default bonding token:
You should be able to see both of these values set in your env with echo $OOV3_ADDRESS and echo $DEFAULT_CURRENCY_ADDRESS
To deploy the Data Asserter contract, run forge create command.
(Note if you hit an error like Error accessing local wallet. Did you set a private key, mnemonic or keystore? then you might be hitting a foundry related issue that should be resolved by updating your foundry installation with foundryup.
Finally, we can verify the deployed (if deployed to a public network) contract with forge verify-contract:
The following section provides instructions on how to interact with the deployed contract from the foundry cast tool, though one can also use it for guidance for interacting through another interface (e.g. Remix or Etherscan).
Export derivation index for the asserting user that will be needed when signing transactions:
Make sure the user address above have sufficient funding for the gas to execute the transactions.
Next, set up the bytes32 encoding for the dataId and data, as discussed in the section. The dataId field will be the simplest command that can be re-produced by independent verifiers. We use bc (arbitrary-precision arithmetic language and calculator) that should be available on most operating systems:
The data field will be the asserted output of the above bc command:
Note that at any point you can look at your env by running printenv within your console to see the things we've set up to this point.
Next, we will call the Data Asserter contract and assert the data point and data ID that we set within our environment. Note that on the Goerli testnet the default bond for the default currency is set to 0. This is done to somewhat simplify the interactions: you don't need to mint yourself any USDC and you don't need to approve the Data Asserter to pull it from your account. Clearly, this is different to how this would be structured in reality but for demonstration purposes it keeps thing easier.
What we are doing here is calling the assertDataFor(bytes32,bytes32,address)with the props DATA_ID, DATA and DATA_ASSERTER, that we set earlier. We are taking the output of the transaction and storing the transactionHash within the ASSERTION_TX variable.
We can fetch the associated assertionId from the DataAssertionResolved event that should be the last event in the assertion transaction. The emitted event has the structure:
We can fetch indexed props from cast by using the receipt function in conjunction with jq. To fetch the 3rd indexed prop (assertionId) from the last event, we would run:
Next, we can view the data asserted object using the --abi-decode call. This will return the props in the assertionData mapping, relating to this structure:
The last prop in the output (resolved) should be false at this moment.
Now, let's move forward 2 hours to go pass the challenge window of the assertion:
Now, we can submit the settlement transaction to the OOV3 as we've passed liveness:
If we call the assertionData mapping again, we'll see that the assertion has settled. The last prop in the output (resolved) should be true:
We can now call the getData method directly and store output in IS_RESOLVED and RESOLVED_DATA variables:
IS_RESOLVED should now be true:
The decoded value of RESOLVED_DATA should be 489 as originally asserted:
This tutorial has shown you how to use the Data Asserter sample tutorial, along with the Optimistic Oracle V3. This is meant to act as a starting point for further contracts to be built on. Next steps should be looking at the other OOV3 tutorials or trying to build your own integration! If you have questions please message us on Discord or create a Github issue and we'll happily help you with your integration.
OptimisticOracleV3Next, we have the callback recipient set to address(this). The OOV3 has the concept of callbacks wherein at the settlement of an assertion the asserter can choose to optionally call out from the OO into another contract. In this context, we want the OOV3 to call back into the Data Asserter contract when the assertion is settled (this will become clearer in the following section).
We have no Sovereign security enabled here (this is an advanced topic and does not need to be covered here).
Default liveness, bond and identifier are set.
No domain is set (this is an external concept that helps 3rd parties identify assertions).
dataAssertion structureif it was resolved as not truthful (deleted) then simply delete it from the temp structure assertionsData
FINDER_ADDRESS: address of the Finder contract used to locate other UMA ecosystem contracts (in order to resolve disputes you would need to use the one from a sandboxed environment). For Goerli, you can use:
export FINDER_ADDRESS=0xE60dBa66B85E10E7Fd18a67a6859E241A243950egit clone https://github.com/UMAprotocol/dev-quickstart-oov3.git
cd dev-quickstart-oov3
forge install constructor(address _defaultCurrency, address _optimisticOracleV3) {
defaultCurrency = IERC20(_defaultCurrency);
oo = OptimisticOracleV3Interface(_optimisticOracleV3);
defaultIdentifier = oo.defaultIdentifier();
} function assertDataFor(
bytes32 dataId,
bytes32 data,
address asserter
) public returns (bytes32 assertionId) { ... } assertionId = oo.assertTruth(
abi.encodePacked(
"Data asserted: 0x", // in the example data is type bytes32 so we add the hex prefix 0x.
ClaimData.toUtf8Bytes(data),
" for dataId: 0x",
ClaimData.toUtf8Bytes(dataId),
" and asserter: 0x",
ClaimData.toUtf8BytesAddress(asserter),
" at timestamp: ",
ClaimData.toUtf8BytesUint(block.timestamp),
" in the DataAsserter contract at 0x",
ClaimData.toUtf8BytesAddress(address(this)),
" is valid."
),
asserter,
address(this), // Callback recipient
address(0), // No sovereign security.
assertionLiveness,
defaultCurrency,
bond,
defaultIdentifier,
bytes32(0) // No domain.
);// OptimisticOracleV3 resolve callback.
function assertionResolvedCallback(bytes32 assertionId, bool assertedTruthfully) public {
require(msg.sender == address(oo));
// If the assertion was true, then the data assertion is resolved.
if (assertedTruthfully) {
assertionsData[assertionId].resolved = true;
DataAssertion memory dataAssertion = assertionsData[assertionId];
emit DataAssertionResolved(dataAssertion.dataId, dataAssertion.data, dataAssertion.asserter, assertionId);
// Else delete the data assertion if it was false to save gas.
} else delete assertionsData[assertionId];
}forge test --match-path *DataAsserter*anvil --fork-url https://goerli.infura.io/v3/xxxexport OOV3_ADDRESS=$(cast call $FINDER_ADDRESS "getImplementationAddress(bytes32)(address)" \
$(cast --format-bytes32-string "OptimisticOracleV3"))
export DEFAULT_CURRENCY_ADDRESS=$(cast call $OOV3_ADDRESS "defaultCurrency()(address)")export DATA_ASSERTER=$(forge create --json src/DataAsserter.sol:DataAsserter \
--mnemonic "$MNEMONIC" \
--constructor-args $DEFAULT_CURRENCY_ADDRESS $OOV3_ADDRESS \
| jq -r .deployedTo)forge verify-contract \
--chain-id $(cast chain-id) \
--constructor-args $(cast abi-encode "constructor(address,address)" \
$DEFAULT_CURRENCY_ADDRESS $OOV3_ADDRESS) $DATA_ASSERTER DataAsserterexport ASSERTER_ID=1export DATA_ID=$(cast --format-bytes32-string "echo '69+420' | bc")
echo "DATA_ID=$(echo $DATA_ID)"export DATA=$(cast --format-bytes32-string $(echo '69+420' | bc))
echo "DATA=$(echo $DATA)"export ASSERTION_TX=$(cast send --json \
--mnemonic "$MNEMONIC" --mnemonic-index $ASSERTER_ID \
$DATA_ASSERTER \
"assertDataFor(bytes32,bytes32,address)" $DATA_ID $DATA $DATA_ASSERTER \
| jq -r .transactionHash) event DataAssertionResolved(
bytes32 indexed dataId,
bytes32 data,
address indexed asserter,
bytes32 indexed assertionId
);export ASSERTION_ID=$(cast receipt --json $ASSERTION_TX | jq -r .logs[-1].topics[3]) struct DataAssertion {
bytes32 dataId; // The dataId that was asserted.
bytes32 data; // This could be an arbitrary data type.
address asserter; // The address that made the assertion.
bool resolved; // Whether the assertion has been resolved.
}cast --abi-decode "assertionsData(bytes32)(bytes32,bytes32,address,bool)" \
$(cast call $DATA_ASSERTER "assertionsData(bytes32)" $ASSERTION_ID)cast rpc evm_increaseTime 7200
cast rpc evm_minecast send --mnemonic "$MNEMONIC" $OOV3_ADDRESS "settleAssertion(bytes32)" $ASSERTION_IDcast --abi-decode "assertionsData(bytes32)(bytes32,bytes32,address,bool)" \
$(cast call $DATA_ASSERTER "assertionsData(bytes32)" $ASSERTION_ID)read -r IS_RESOLVED RESOLVED_DATA \
< <(cast --abi-decode "getData(bytes32)(bool,bytes32)" \
$(cast call $DATA_ASSERTER "getData(bytes32)" $ASSERTION_ID) \
| awk '{s=(NR==1?s:s " ")$0}END{print s}') echo $IS_RESOLVEDcast --parse-bytes32-string $RESOLVED_DATAexport MNEMONIC="test test test test test test test test test test test junk"The Full Policy Escalation Manager is an example implementation of Escalation Manager that allows for a high level of control over the arbitration process in the Optimistic Oracle V3. It can be used to set various policy parameters such as who is able to assert truths, who is able to file disputes, and whether disputes should be arbitrated via the escalation manager or the UMA Data Verification Mechanism (DVM). By using the Escalation Managers, such as the Full Policy Escalation Manager, users can better tailor the arbitration process to suit their specific needs and security requirements.
An Escalation Manager is a smart contract that is used in the Optimistic Oracle V3 to handle the escalation policy for assertions and can also be used to arbitrate disputes. When one party makes an assertion, it might be challenged by another, known as the disputer. In the event of a dispute, the Escalation Manager is used to decide how the dispute should be handled and how the Optimistic Oracle V3 should respond to it.
The Full Policy Escalation Manager is an Escalation Manager implementation that allows the contract owner to set all policy parameters and store arbitration resolutions for the Escalation Manager.
Some of the key functionality that the Full Policy Escalation Manager allows are:
Enabling a whitelist of asserting callers, asserters and disputers. This allows the owner to limit who can assert truths, and who can dispute assertions.
Determining whether disputes should be arbitrated by the Escalation Manager or by the Data Verification Mechanism (DVM).
Determining whether the resolution of a potential dispute arbitrated by the Oracle should be disregarded (i.e a disputed assertion defaults to false outcome).
Storing and managing the arbitration resolutions for a given identifier, time and ancillary data.
This smart contract is ideal for use cases where a high degree of control over the behaviour of the Escalation Manager is needed, and where the owner wants to have a say in how disputes are handled and acts as a good starting point for projects that want to build their own escalation managers that implement custom logic.
The FullPolicyEscalationManager can be used in a variety of ways depending on the specific needs of the project. Below are a few examples of possible use cases and how to configure the escalation manager for each:
Blocking assertions by untrusted parties: In this case, the project may want to prevent assertions from being made by certain parties that are not trusted. To accomplish this, the blockByAssertingCaller and/or blockByAsserter parameters can be set to true and the corresponding whitelists can be populated with trusted parties using the setAssertingCallerWhitelist and setAsserterWhitelist functions.
Validation of disputers: In some cases, the project may want to prevent disputes from being filed by untrusted parties. To accomplish this, the validateDisputers parameter can be set to true and the whitelistedDisputeCallers whitelist can be populated with trusted parties using the setDisputeCallerWhitelist function.
Allowing arbitration via the escalation manager: By default, disputes are arbitrated via the UMA DVM. However, in some cases, the project may want to use the escalation manager to arbitrate disputes instead. To accomplish this, the arbitrateViaEscalationManager parameter can be set to true.
Discarding the oracle resolution: In some cases, the project may want to disregard the oracle's resolution when arbitrating disputes. To accomplish this, the discardOracle parameter can be set to true.
Custom arbitration resolution: If the project wants to define a custom resolution for a given identifier, time, and ancillary data, it can be set using the setArbitrationResolution function.
Mixing different options: The FullPolicyEscalationManager can be customized to mix different options, such as allowing arbitration via the escalation manager, but also blocking assertions by untrusted parties, or validating disputers but also allowing custom arbitration resolution.
It's important to note that the values of blockByAssertingCaller, blockByAsserter, validateDisputers, arbitrateViaEscalationManager, discardOracle are set to false by default.
EscalationManagerConfigured: Emitted when the escalation manager is configured using the configureEscalationManager function. The event contains the following parameters:
blockByAssertingCaller: A boolean indicating whether assertions are allowed only by whitelisted asserting callers.
blockByAsserter: A boolean indicating whether assertions are allowed only by whitelisted asserters.
validateDisputers: A boolean indicating whether the escalation managershould validate disputers via the whitelistedDisputeCallers mapping.
arbitrateViaEscalationManager: A boolean indicating whether it is determined that the escalation manager should arbitrate disputes.
discardOracle: A boolean indicating whether the escalation manager should disregard the Oracle’s resolution of disputes.
ArbitrationResolutionSet: Emitted when an arbitration resolution is set using the setArbitrationResolution function. The event contains the following parameters:
identifier: The identifier of the assertion.
time
DisputeCallerWhitelistSet: Emitted when a dispute caller is added or removed from the whitelistedDisputeCallers mapping using the addDisputeCallerToWhitelist and removeDisputeCallerFromWhitelist functions. The event contains the following parameters:
disputeCaller: The address of the dispute caller that was added or removed from the whitelist.
AssertingCallerWhitelistSet: Emitted when an asserting caller is added or removed from the whitelistedAssertingCallers mapping using the addAssertingCallerToWhitelist and removeAssertingCallerFromWhitelist functions. The event contains the following parameters:
assertingCaller: The address of the asserting caller that was added or removed from the whitelist.
AsserterWhitelistSet: Emitted when an asserter is added or removed from the whitelistedAsserters mapping using the addAsserterToWhitelist and removeAsserterFromWhitelist functions. The event contains the following parameters:
asserter: The address of the asserter to add.
This function returns the Assertion Policy defined by the contract's parameters and functions.
Parameters
assertionId: the ID of the assertion to get the policy for.
Returns
AssertionPolicy memory: an object that contains the following properties:
blockAssertion: a boolean indicating whether the assertion is blocked or not.
arbitrateViaEscalationManager: a boolean indicating whether the arbitration should be done via the escalation manager if it is configured.
discardOracle: a boolean indicating whether to ignore the Oracle (DVM or EM) resolution if it is configured.
validateDisputers: a boolean indicating whether to validate disputers if it is configured.
Notes
If no configuration is done after deployment, this function returns an all false default policy.
The getPrice function allows developers to retrieve the resolved price for a given identifier and timestamp. It replicates the interface of the corresponding DVM function to allow the user to use his own dispute arbitration system when arbitrating via the escalation manager in a DVM-compatible manner. It is useful when you want to get the resolved price for a specific request.
Parameters
identifier: A unique identifier that identifies the price requested.
time: A unix timestamp of the price request.
ancillaryData: Arbitrary data appended to a price request to give the voters more info from the caller.
Returns
int256: representing the resolved price for the given identifier and timestamp.
Notes
If the price is not available, the method reverts. Also, the function requires that the arbitration resolution has been set before calling it.
This function returns whether a given disputerCaller is authorized to dispute a given assertionId or not.
Parameters
assertionId: The ID of the assertion to check the disputerCaller for.
disputeCaller: The address of the disputeCaller to check.
Returns
bool: true if the disputerCaller is authorized to dispute the assertion, false otherwise.
Notes
In order for this function to be used by the Optimistic Oracle V3, validateDisputers must be set to true.
The whitelistedDisputeCallers is a mapping that contains the addresses of the authorized disputers, which are set through the setDisputeCallerInWhitelist function.
This function is used to configure the escalation manager and define the assertion policy for each configuration's rules.
_blockByAssertingCaller: A boolean value that indicates if assertions are allowed only by whitelisted asserting callers.
_blockByAsserter: A boolean value that indicates if assertions are allowed only by whitelisted asserters.
_validateDisputers: A boolean value that indicates if the escalation manager should validate disputers via whitelistedDisputeCallers.
_arbitrateViaEscalationManager: A boolean value that indicates if the escalation manager should arbitrate instead of the DVM.
_discardOracle: A boolean value that indicates if the escalation manager should disregard the Oracle's (DVM or EM) resolution.
Notes
This function can only be called by the contract's owner.
It is important to note that this function only activates the rules that will be executed, each rule must additionally be defined using the other functions.
The _blockByAsserter must be true if _blockByAssertingCaller is true.
When this function is called, an event EscalationManagerConfigured is emitted with the parameters of the function call.
This function is used to set the arbitration resolution for a given identifier, time, and ancillary data. This function should be used by the contract owner whenever a dispute arises and it should be arbitrated by the Escalation Manager. The owner of the contract is responsible for determining how to resolve the dispute.
identifier: A unique identifier that represents the price requested. This is used to identify the price request in question.
time: A unix timestamp of the price request.
ancillaryData: Arbitrary data that is appended to a price request to give the voters more information from the caller.
arbitrationResolution: A boolean value that indicates if the assertion should be resolved as true (true) or false (false).
This function is only callable by the owner of the contract.
This function requires that the arbitrationResolutions[requestId].valueSet is equal to false, otherwise the function will revert with the error message "Arbitration already resolved".
A ArbitrationResolutionSet event is emitted with the parameters identifier, time, ancillaryData, and arbitrationResolution when this function is called.
The getRequestId function is used to generate a requestId to uniquely identify the price request. The requestId is generated from the identifier, time, and ancillaryData parameters.
The setDisputeCallerInWhitelist function allows the owner of the FullPolicyEscalationManager contract to add or remove a given address (disputeCaller) to the whitelist of addresses that are able to file disputes.
disputeCaller: The address of the dispute caller to add or remove from the whitelist.
value: A boolean value that represents whether the disputeCaller is being added (true) or removed (false) from the whitelist.
This function is only used if the validateDisputers parameter is set to true. When a dispute caller is added or removed from the whitelist, the DisputeCallerWhitelistSet event is emitted with the disputeCaller and value as the arguments.
This function allows the owner of the contract to add or remove an address from the whitelist of asserting callers that are authorized to make assertions.
assertingCaller: The address of the asserting caller to add or remove from the whitelist.
value: A boolean value that represents whether the asserting caller is being added (true) or removed (false) from the whitelist.
This function can only be called by the owner of the contract.
An event AssertingCallerWhitelistSet is emitted upon the successful execution of this function, which includes the assertingCaller and the value as the arguments.
The whitelist of asserting callers is used when the blockByAssertingCaller configuration is set to true. In this case, only addresses in the whitelist are allowed to make assertions.
This function allows an owner to add or remove an address from the whitelist of authorized asserters.
Parameters
asserter: The address of the asserter to add or remove from the whitelist.
value: A boolean value that determines whether the asserter is added or removed from the whitelist. true represents adding the asserter to the whitelist and false represents removing the asserter from the whitelist.
Notes
This function can only be called by the contract owner.
This function must be used in conjunction with setWhitelistedAssertingCallers in order to have an effect. This means that if setWhitelistedAssertingCallers is set to true, the assertion will only be made by an address that is in both whitelists whitelistedAssertingCallers and whitelistedAsserters.
When an asserter is added or removed from the whitelist, an event AsserterWhitelistSet is emitted with the asserter and value as the arguments.
To get started with the Full Policy Escalation Manager, the first step is to deploy the contract on the EVM network. This can be done using hardhat and a library such as ethers.js. Here is an example of how to deploy the contract:
Once the contract is deployed, it can be configured to handle disputes in different ways, depending on the use case. The configureEscalationManager function can be used to set the rules for how disputes should be handled. Here are some examples of how to configure the contract for different use cases:
Example 1:
Example 2:
Example 3:
The Full Policy Escalation Manager can be configured for a variety of use cases depending on the requirements. The examples above show how to deploy the contract, configure it for different use cases and whitelist asserting callers, asserters and disputers. Keep in mind that the contract can only be configured by the owner and that the parameters of configureEscalationManager function must be set according to the desired use case.
Using the Optimistic Oracle to allow for verification of insurance claims
This section covers the insurance claims arbitration contract, which is available in the developer's quick-start repo. This tutorial shows an example of how insurance claims can be resolved and settled through the Optimistic Oracle V2 contract.
You will find out how to test and deploy this smart contract and how it integrates with the Optimistic Oracle.
This smart contract allows insurers to issue insurance policies by depositing the insured amount, designating the insured beneficiary, and describing the insured event.
Anyone can submit a claim that the insured event has occurred at any time. Insurance Arbitrators resolve the claim through the Optimistic Oracle by passing a question with a description of the insured event in ancillary data using the YES_OR_NO_QUERY price identifier specified in .
If the claim is confirmed and settled through the Optimistic Oracle, this contract automatically pays out insurance coverage to the beneficiary. If the claim is rejected, the policy continues to be active and ready for subsequent claim attempts.
Clone the UMA dev-quickstart repository and install the dependencies. To install dependencies, you will need to install the long-term support version of nodejs, currently Nodejs v16, and yarn. You can then install dependencies by running yarn with no arguments:
We will need to run the following command to compile the contracts and make the Typescript interfaces so that they are easy to work with:
The contract discussed in this tutorial can be found at dev-quickstart/contracts/InsuranceArbitrator.sol () within the repo.
_finder parameter in the constructor points the Insurance Arbitrator to the Finder contract that stores the addresses of the rest of the UMA contracts. The Finder address can be fetched from the relevant file, if you are on a live network, or you can provide your own Finder instance if deploying UMA in your own sandboxed testing environment.
_currency parameter in the constructor identifies the token used for settlement of insurance claims, as well as the bond currency for proposals and disputes. This token should be approved as whitelisted UMA collateral. Please check for production networks or call getWhitelist() on the contract for any of the test networks.
Alternatively, you can approve a new token address with addToWhitelist method in the Address Whitelist contract if working in a sandboxed UMA environment.
_timer is used only when running unit tests locally to simulate the advancement of time. For all the public networks (including testnets) the zero address should be used.
As part of initialization, the oo variable is set to the address of the OptimisticOracleV2 implementation as discovered through getImplementationAddress method in the contract.
issueInsurance method allows any insurer to deposit insuredAmount of currency tokens by designating an insurance beneficiary (insuredAddress) and defining the insured event (insuredEvent). Before calling this method, the insurer should have approved this contract to spend the required amount of currency tokens.
Internally, the issued policy is stored in the insurancePolicies mapping using the calculated policyId key that is generated by hashing the current block number with the provided insurance parameters in the internal _getPolicyId function.
After pulling insuredAmount from the caller in the issueInsurance method, the contract emits a PolicyIssued event including the policyId parameter that should be used when claiming insurance.
Anyone can submit an insurance claim on the issued policy by calling the submitClaim method with the relevant policyId parameter. This method will initiate both a data request and proposal with the Optimistic Oracle. A proposal bond is required, hence the caller should have approved this contract to spend the required amount of currency tokens for the proposal bond.
After checking that the policyId represents a valid unclaimed insurance policy, the contract gets the current timestamp and composes ancillaryData that will be required for making requests and proposals to the Optimistic Oracle:
The resulting timestamp and ancillaryData parameters are hashed in the internal _getClaimId method that is used as a key when storing the linked policyId in the insuranceClaims mapping. This information will be required when receiving a callback from the Optimistic Oracle.
The concatenated ancillaryData will have a valid question as specified in for YES_OR_NO_QUERY price identifier.
An Optimistic Oracle data request is initiated without providing any proposer reward since the proposal will be done within the submitClaim method:
Before the proposal is made, the Optimistic Oracle allows the requesting contract (this Insurance Arbitrator) to set additional parameters like bonding, liveness, and callback settings. This requires passing the same priceIdentifier, timestamp, and ancillaryData parameters to identify the request.
Total bond to be pulled from the claim initiator consists of the Optimistic Oracle proposer bond and final fee for the relevant currency token. This contract sets the proposer bond as a fixed percentage (constant oracleBondPercentage) from insuredAmount. When calling the setBond method, the Optimistic Oracle calculates and returns the total bond that would be pulled when making the proposal:
Optimistic Oracle liveness is set by calling the setCustomLiveness method. This contract uses 24 hours so that verifiers have sufficient time to check the claim, but one can adjust the optimisticOracleLivenessTime constant for testing. (You probably don't want to wait a full day to resolve your test requests!)
In contrast to earlier versions, the Optimistic Oracle V2 by default does not use callbacks and requesting contracts have to explicitly subscribe to them if intending to perform any logic when a data request has changed state. Here, in calling setCallbacks, this contract only subscribes to a callback for settlement, as implemented in the priceSettled method. (Note: Subscribing to any other callbacks that are not implemented in the requesting contract would make data requests unresolvable.)
After totalBond amount of currency token is pulled from the claim initiator and approved to be taken by Optimistic Oracle, this contract proposes 1e18 representing an answer of YES to the raised question. Requesting and proposing affirmative answers atomically allows us to reduce the number of steps taken by end users and it is most likely expected that the insured beneficiary would be initiating the claim.
For the sake of simplicity this contract does not implement a dispute method, but the disputer can dispute the submitted claim directly through Optimistic Oracle before the liveness passes by calling its disputePrice method:
The disputer should pass the address of this Insurance Arbitrator contract as requester and all the other parameters from the original request when the claim was initiated as emitted by the Optimistic Oracle in its RequestPrice event.
If the claim is disputed, the request is escalated to the UMA DVM and it can be settled only after UMA voters have resolved it. To learn more about the DVM, see the docs section on the DVM: .
Similar to disputes, claim settlement should be initiated through the Optimistic Oracle contract by calling its settle method with the same parameters:
In case the liveness has expired or a dispute has been resolved by the UMA DVM, this call would initiate a priceSettled callback in the Insurance Arbitrator contract:
Based on the received callback parameters, this contract can identify the relevant claimId that is used to get the stored insurance policy:
Importantly, all callbacks should be restricted to accept calls only from the Optimistic Oracle to avoid someone spoofing a resolved answer:
Depending on the resolved answer, this contract would either pay out the insured beneficiary and delete the insurance (in case of 1e18 representing the answer YES, the insurance claim was valid) or reject the payout and re-open the policy for any subsequent claims:
All the unit tests covering the functionality described above are available . To execute all of them, run:
Before deploying the contract check the comments on available environment variables in .
In the case of the Görli testnet, the defaults would use the Finder instance that references the implementation for resolving DVM requests. This exposes a pushPrice method to be used for simulating a resolved answer in case of disputed proposals. Also, the default Görli deployment would use the already whitelisted TestnetERC20 currency that can be minted by anyone using its allocateTo method.
To deploy the Insurance Arbitrator contract on Görli, run:
Optionally you can verify the deployed contract on Etherscan:
The following section provide instructions on how to interact with the deployed contract from the Hardhat console, though one can also use it for guidance for interacting through another interface (e.g. Remix or Etherscan).
Start Hardhat console with:
From the Hardhat console, start by adding the required getAbi dependency for interacting with UMA contracts and use the first two accounts as insurer and insured beneficiary:
Grab the deployed Insurance Arbitrator contract:
Assuming TestnetERC20 was used as currency when deploying, mint the required insurance amount (e.g. 10,000 TEST tokens) and approve the Insurance Arbitrator to pull them:
Issue the insurance policy and grab the resulting policyId from the emitted PolicyIssued event:
First calculate the expected proposer bond:
Fetch the expected final fee from the Store contract (which is discovered through the Finder):
Calculate the expected total bond and provide funding/approval for the insured claimant:
Now initiate the insurance claim and grab request details from the RequestPrice event emitted by the Optimistic Oracle:
Before liveness passes, the insurer can dispute the claim through the Optimistic Oracle. First, they must fund and approve with the same bonding amount:
If you are on a testnet like Göerli, in order to simulate UMA voting on a testnet, you can use the :
Now initiate the dispute and grab the vote request details from the PriceRequestAdded event emitted by the Mock Oracle:
Before settling the claim, we can take a look at the vote request as seen by UMA voters:
The ancillaryData should start with q:"Had the following insured event occurred as of request timestamp: Bad things have happened?". It is then followed by the ooRequester key with our Insurance Arbitrator address in its value.
In order to simulate YES as the resolved answer we would pass 1e18 as the price parameter in the Mock Oracle pushPrice method:
Now we can settle the request through the Optimistic Oracle and observe the emitted ClaimAccepted from our Insurance Arbitrator contract:
The above settlement transaction should also transfer insuredAmount tokens to the insured beneficiary as well as return the proposer bond to the claim initiator.
Alternatively, if 0 value was resolved, the settlement transaction should emit the ClaimRejected event without paying out the insuredAmount and returning the bond to the disputer, along with half of the proposer's bond.
const hre = require("hardhat");
import { FullPolicyEscalationManagerEthers__factory } from "@uma/contracts-node";
const { getContractFactory } = hre.ethers;
const { getAddress } = require("@uma/contracts-node");
async function main() {
console.log("Running FullPolicyEscalationManager Deployments🔥");
const networkId = Number(await hre.getChainId());
const optimisticOracleV3 = getAddress("OptimisticOracleV3", networkId);
const fullPolicyEscalationManagerFactory: FullPolicyEscalationManagerEthers__factory = await getContractFactory(
"FullPolicyEscalationManager"
);
const fullPolicyEscalationManager = await fullPolicyEscalationManagerFactory.deploy(optimisticOracleV3);
console.log("Deployed FullPolicyEscalationManager: ", fullPolicyEscalationManager.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});//Configure the contract to block assertions by asserting callers that are not whitelisted
await fullPolicyEscalationManager.configureEscalationManager(true, false, false, false, false);
//Whitelist an asserting caller and asserter
await fullPolicyEscalationManager.setWhitelistedAssertingCallers("0x123456789abcdef0123456789abcdef0123456789", true);//Configure the contract to validate disputers and arbitrate via the escalation manager
await fullPolicyEscalationManager.configureEscalationManager(false, false, true, true, false);
//Whitelist a dispute caller
await fullPolicyEscalationManager.setDisputeCallerInWhitelist("0x123456789abcdef0123456789abcdef0123456789", true);//Configure the contract to disregard the oracle's resolution
await fullPolicyEscalationManager.configureEscalationManager(false, false, false, false, true);ancillaryData: The ancillary data of the assertion.
resolution: The resolution of the arbitration.
whitelisted: A boolean indicating whether the dispute caller was added (true) or removed (false) from the whitelist.whitelisted: A boolean indicating whether the asserting caller was added (true) or removed (false) from the whitelist.whitelisted: true represents adding and false represents removing the asserter from the whitelist.git clone [email protected]:UMAprotocol/dev-quickstart.git
cd dev-quickstart
yarnyarn hardhat compile constructor(
FinderInterface _finder,
address _currency,
address _timer
) Testable(_timerAddress) {
finder =_finderAddress;
currency = IERC20(_currency);
oo = OptimisticOracleV2Interface(finder.getImplementationAddress(OracleInterfaces.OptimisticOracleV2));
} function issueInsurance(
string calldata insuredEvent,
address insuredAddress,
uint256 insuredAmount
) external returns (bytes32 policyId) ... function submitClaim(bytes32 policyId) ... uint256 timestamp = getCurrentTime(); // note that `getCurrentTime` is exported from testable to enable easy time manipulation.
bytes memory ancillaryData = abi.encodePacked(ancillaryDataHead, claimedPolicy.insuredEvent, ancillaryDataTail);
bytes32 claimId = _getClaimId(timestamp, ancillaryData);
insuranceClaims[claimId] = policyId; oo.requestPrice(priceIdentifier, timestamp, ancillaryData, currency, 0); uint256 proposerBond = (claimedPolicy.insuredAmount * oracleBondPercentage) / 1e18;
uint256 totalBond = oo.setBond(priceIdentifier, timestamp, ancillaryData, proposerBond); oo.setCustomLiveness(priceIdentifier, timestamp, ancillaryData, optimisticOracleLivenessTime); oo.setCallbacks(priceIdentifier, timestamp, ancillaryData, false, false, true); oo.proposePriceFor(msg.sender, address(this), priceIdentifier, timestamp, ancillaryData, int256(1e18)); function disputePrice(
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) ... function settle(
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) ... function priceSettled(
bytes32, // identifier passed by Optimistic Oracle, but not used here as it is always the same.
uint256 timestamp,
bytes memory ancillaryData,
int256 price
) ... bytes32 claimId = _getClaimId(timestamp, ancillaryData); require(address(oo) == msg.sender, "Unauthorized callback"); // Deletes insurance policy and transfers claim amount if the claim was confirmed.
if (price == 1e18) {
delete insurancePolicies[policyId];
currency.safeTransfer(claimedPolicy.insuredAddress, claimedPolicy.insuredAmount);
emit ClaimAccepted(claimId, policyId);
// Otherwise just reset the flag so that repeated claims can be made.
} else {
insurancePolicies[policyId].claimInitiated = false;
emit ClaimRejected(claimId, policyId);
}yarn test test/InsuranceArbitrator/*NODE_URL_5=YOUR_GOERLI_NODE MNEMONIC=YOUR_MNEMONIC yarn hardhat deploy --network goerli --tags InsuranceArbitratorETHERSCAN_API_KEY=YOUR_API_KEY yarn hardhat etherscan-verify --network goerli --license AGPL-3.0 --force-license --solc-inputNODE_URL_5=YOUR_GOERLI_NODE MNEMONIC=YOUR_MNEMONIC yarn hardhat console --network goerliconst { getAbi } = require("@uma/contracts-node");
const [insurer, insured] = await ethers.getSigners();const insuranceArbitratorDeployment = await deployments.get("InsuranceArbitrator");
const insuranceArbitrator = new ethers.Contract(
insuranceArbitratorDeployment.address,
insuranceArbitratorDeployment.abi,
ethers.provider
);const insuredAmount = ethers.utils.parseEther("10000");
const currency = new ethers.Contract(await insuranceArbitrator.currency(), getAbi("TestnetERC20"), ethers.provider);
await (await currency.connect(insurer).allocateTo(insurer.address, insuredAmount)).wait();
await (await currency.connect(insurer).approve(insuranceArbitrator.address, insuredAmount)).wait();const issueReceipt = await (await insuranceArbitrator.connect(insurer).issueInsurance(
"Bad things have happened",
insured.address,
insuredAmount
)).wait();
const policyId = (await insuranceArbitrator.queryFilter(
"PolicyIssued",
issueReceipt.blockNumber,
issueReceipt.blockNumber
))[0].args.policyId;const proposerBond = insuredAmount.mul(await insuranceArbitrator.oracleBondPercentage()).div(ethers.utils.parseEther("1"));const finder = new ethers.Contract(await insuranceArbitrator.finder(), getAbi("Finder"), ethers.provider);
const store = new ethers.Contract(await finder.getImplementationAddress(
ethers.utils.formatBytes32String("Store")),
getAbi("Store"),
ethers.provider);
const finalFee = (await store.computeFinalFee(currency.address)).rawValue;const totalBond = proposerBond.add(finalFee);
await (await currency.connect(insured).allocateTo(insured.address, totalBond)).wait();
await (await currency.connect(insured).approve(insuranceArbitrator.address, totalBond)).wait();const oo = new ethers.Contract(await insuranceArbitrator.oo(), getAbi("OptimisticOracleV2"), ethers.provider);
const claimReceipt = await (await insuranceArbitrator.connect(insured).submitClaim(policyId)).wait();
const request = (await oo.queryFilter("RequestPrice", claimReceipt.blockNumber, claimReceipt.blockNumber))[0].args;await (await currency.connect(insurer).allocateTo(insurer.address, totalBond)).wait();
await (await currency.connect(insurer).approve(oo.address, totalBond)).wait();const mockOracle = new ethers.Contract(await finder.getImplementationAddress(
ethers.utils.formatBytes32String("Oracle")),
getAbi("MockOracleAncillary"),
ethers.provider);const disputeReceipt = await (await oo.connect(insurer).disputePrice(
request.requester,
request.identifier,
request.timestamp,
request.ancillaryData
)).wait();
const voteRequest = (await mockOracle.queryFilter(
"PriceRequestAdded",
disputeReceipt.blockNumber,
disputeReceipt.blockNumber
))[0].args;console.log("identifier:", ethers.utils.parseBytes32String(voteRequest.identifier));
console.log("time:", Number(voteRequest.time));
console.log("ancillaryData:", ethers.utils.toUtf8String(voteRequest.ancillaryData));await (await mockOracle.connect(insured).pushPrice(
voteRequest.identifier,
voteRequest.time,
voteRequest.ancillaryData,
ethers.utils.parseEther("1")
)).wait();const settleReceipt = await (await oo.connect(insured).settle(
request.requester,
request.identifier,
request.timestamp,
request.ancillaryData
)).wait();
const claimSettlementEvent = (await insuranceArbitrator.queryFilter(
"ClaimAccepted",
settleReceipt.blockNumber,
settleReceipt.blockNumber
))[0];
console.log(claimSettlementEvent);Description:
Description:
Description:
Description:
Description:
Description:
Description:
Description:
Description:
Description:
BigInt
Provides a lower bound on the number of votes a user has correctly voted for. Users may not have retrieved rewards for all of their correct votes
votesCommited
Int!
String!
isOnWhitelist
Boolean!
Is token currently whitelisted as collateral
finalFee
BigDecimal
PriceRequestRound
PriceRequestRound entity corresponding to the last round of voting
time
BigInt!
identifier
PriceIdentifier!
PriceIdentifier for the request
ancillaryData
String
resolutionTransaction
Bytes
Transaction where the resolution of the request took place
resolutionTimestamp
Bigint
Timestamp when the resolution of the request took place
resolutionBlock
BigInt
Block number when the resolution of the request took place
rounds
List of all the rounds involved in this PriceRequest
committedVotes
List of all the votes committed on this request
revealedVotes
List of all the votes revealed on this request
rewardsClaimed
List of all the rewards claimed events for this request
String
time
BigInt!
snapshotId
BigInt
votersAmount
BigDecimal!
Total amount of users who voted on this round
votersClaimedAmount
BigDecimal!
Total amount of users who claimed rewards on this round
totalVotesRevealed
BigDecimal!
totaRewardsClaimed
BigDecimal!
totalSupplyAtSnapshot
BigDecimal
tokenVoteParticipationRatio
BigDecimal
Ratio of the total supply of tokens that were weighted on this vote
tokenVoteParticipationPercentage
BigDecimal
Ratio of correct voters over total voters on this price request
votersEligibleForRewardRatio
BigDecimal
Ratio of correct voters over total voters on this price request
votersEligibleForRewardsPercentage
BigDecimal
Percentage of correct voters over total voters on this price request
votersClaimRatio
BigDecimal
Ratio of correct voters who claimed their rewards
votersClaimedPercentage
BigDecimal
Percentage of correct voters who claimed their rewards
tokensClaimedRatio
BigDecimal
Ratio of rewards claimed over total supply of voting token
tokensClaimedPercentage
BigDecimal
Percentage of rewards claimed over total supply of voting token
getPercentageRaw
BigDecimal
getPercentage expressed exactly as in the contract. 1 = 100%
getPercentage
BigDecimal
getPercentage expressed as a percentage value
inflationRateRaw
BigDecimal
inflationRate expressed exactly as in the contract. 1 = 100%
inflationRate
BigDecimal
inflationRate expressed as a percentage value
winnerGroup
VoterGroup
committedVotes
revealedVotes
groups
rewardsClaimed
totalVoteAmount
BigDecimal!
totalVoteAmount
BigInt
votersAmount
BigDecimal!
won
Boolean!
PriceRequest!
time
BigInt!
round
PriceRequestRound!
voter
User!
PriceRequest!
time
BigInt!
round
PriceRequestRound!
price
BigInt!
voter
User!
numTokens
BigInt!
group
VoterGroup!
PriceRequest!
time
BigInt!
round
PriceRequestRound!
claimer
User!
numTokens
BigInt!
NumTokens will be 0 if the claim is not 'valid'. This can happen if the function was called for a voter who didn't get the correct vote for example
group
VoterGroup!
id
ID!
Utility entity that links data from a single Ethereum address. Id of the entity is the Ethereum address itself
address
Bytes!
countReveals
BigInt
Number of price requests that this user has revealed a vote for, and therefore participated in as a voter
id
ID!
Represents approved collateral that is whitelisted in the AddressWhitelist and whose fees are set in the Store. Id of the entity is its address
decimals
Int!
name
String!
id
ID!
isSupported
Boolean!
Depicts whether this PriceIdentifier is currently among the identifiers supported on the whitelist. It will only be false if it was removed from the whitelist
priceRequests
List of all the PriceRequest entities related to this particular PriceIdentifier
id
ID!
ID is the PriceIdentifier ID + the timestamp
isResolved
Boolean!
Depicts whether the request has been resolved
price
BigInt
Price resolved for this request
id
ID!
ID is the PriceIdentifier ID + the timestamp + the roundId + ancillaryData (if available)
request
PriceRequest!
identifier
PriceIdentifier!
id
ID!
Just a helper entity to group voters who voted the same price result. ID is composed of round ID + voted price
price
BigInt!
round
PriceRequestRound!
id
ID!
Committed votes won't show the price until a reveal happens and a RevealedVote is created
identifier
PriceIdentifier!
ancillaryData
String
id
ID!
identifier
PriceIdentifier!
ancillaryData
String
id
ID!
identifier
PriceIdentifier!
ancillaryData
String
id
ID!
This entity represents a contract that can make price requests to the DVM. ID is the address of the contract
creator
Bytes!
registrationTimestamp
BigInt!
countRetrievals
symbol
latestRound
ancillaryData
votes
request
request
request