The Tellor Module belongs to the Zodiac collection of tools, which can be accessed through the Zodiac App available on Gnosis Safe, as well as in this repository.
If you have any questions about the Tellor Module, join the Tellor Discord. For more information about the Zodiac collection of tools, join the Gnosis Discord.
This module allows on-chain execution based on the outcome of Snapshot proposals reported by the Tellor oracle. This module is a Tellor implementation of the Reality Module.
The Snapshot
query consists of a proposal ID (an IPFS hash), which can be used to provide more information for the transaction to be executed.
An array of EIP-712-based transaction hashes represent the transactions that should be executed. It is only possible to execute transactions related to a specific proposalId
and txHashes
once.
When the query response has resolved to true
, meaning that the transactions should be executed, they are submitted to the immutable executor defined in the module. Transactions that resolve to false
cannot be executed by the module.
This module is intended to be used with Gnosis Safe, but it is ultimately framework agnostic. For more information about the Snapshot query type, visit the Snapshot dataspecs.
This module can be setup either using the Zodiac App's UI or by using command line tools; both methods allow for connecting to Snapshot.
View docs for using the command line
- Submit proposals uniquely identified by a
proposalId
and an array oftxHashes
, to create a Tellor query that validates the execution of the connected transactions. - Proposals can be marked invalid by the
executor
usingmarkProposalInvalid
, thereby preventing the execution of the transactions related to that proposal. - A
cooldown
can be specified representing the minimum amount of time required to pass after the query has been answered before the transactions can be executed.
- Add the proposal to the Tellor Module via the
addProposal
method. - The Snapshot proposal needs to pass to approve it for execution.
- A staked Tellor reporter submits the proposal result to the oracle.
- Once the result has been submitted and the
cooldown
period has passed, the transaction(s) can be executed viaexecuteProposal
.
The nonce
of a transaction makes it possible to have two transactions with the same to
, value
and data
but still generate a different transaction hash. This is important as all hashes in the txHashes
array should be unique. To make sure that this is the case, the module will always use the index
of the transaction hash inside the txHashes
array as a nonce. So the first transaction to be executed has the nonce
with the value 0
, the second with the value 1
, and so on.
Therefore we can simplify it to the following statement: The nonce
of a Tellor Module transaction is equal to the index
of that transaction's hash in the txHashes
array.
The Tellor Module requires proposal transactions are successful (e.g. transactions should not internally revert for any reason). If any of the transactions of a proposal fail, it will not be possible to continue with the execution of the following transactions. This is to prevent subsequent transactions being executed in a scenario in which earlier transactions failed due to the gas limit being too low or due to other errors.
Transactions that failed will not be marked as executed, and therefore, they can be executed at any later point in time. This is a potential risk, and therefore it is recommended to either set a result expiration time or invalidate the proposal (e.g. via another proposal).
The Tellor Module can be configured so that positive results will expire after a certain time. This can be done by calling setResultExpiration
with a duration in seconds. If the transactions related to the proposal are not executed before the result expires, it will not be possible to execute them. This is useful in the case of transactions that revert and therefore cannot be executed in order to prevent them from being unexpectedly executed in the future. Negative results (no or invalid) cannot expire.
Note: If the expiration time is set to 0
, results will never expire. This also means results that expired before will become available again. To prevent this, it is recommended to call markProposalWithExpiredResultAsInvalid
immediately after any proposal expires (or on all outstanding expired results prior to setting the expiration date to 0
). This will mark a proposal with an expired result as invalid. This method can be called by anyone.
EIP-712 is used to generate the hashes for the transactions to be executed. The following EIP-712 domain and types are used.
{
EIP712Domain: [
{ type: "uint256", name: "chainId" },
{ type: "address", name: "verifyingContract" }
]
}
{
Transaction: [
{ type: "address", name: "to" },
{ type: "uint256", name: "value" },
{ type: "bytes", name: "data" },
{ type: "uint8", name: "operation" },
{ type: "uint256", name: "nonce" }
]
}
If you've deployed a Tellor Module through the Zodiac frontend, you may be wondering how to connect it to Snapshot and execute a proposal. The steps for achieving this are as follows.
- Ensure you have access to a Snapshot space.
- Visit snapshot.org and navigate to your Snapshot space.
- Click on "Settings."
- Navigate to the "Advanced" tab.
- In the "Plugins" section, select "Add plugin."
- Search for and select "Gnosis SafeSnap."
- You'll encounter several plugin inputs:
{
"safes": [
{
"network": "",
"umaAddress": "",
"tellorAddress": "",
"realityAddress": ""
}
]
}
- Fill in the
network
field with the network ID where your Tellor module contract is deployed. FortellorAddress
, input the address of your Tellor module contract, typically deployed via the Gnosis Safe frontend. - Click "Add Plugin."
- In your Snapshot space, select "New Proposal."
- Enter your proposal's name and description, then click "Continue."
- Under "Type," choose "Basic Voting" and then select "Continue."
- Add the transactions you wish to execute from your Gnosis safe.
- Click "Publish."
- Once published, your proposal page will display an "Information" panel. Click the "IPFS" link (e.g., "https://snapshot.mypinata.cloud/ipfs/bafkreia5v5qgwurmky4vy5orpxniptlswefipla6rmbjw4jjzoqtgbkdfi". Copy and save the entire hash at the end of this URL. This is your
proposalId
.
Your community is now ready to participate in the Snapshot vote. Meanwhile, add your proposal to the Tellor module through the Gnosis Safe/Zodiac frontend.
- In the Zodiac frontend, select your TellorModule.
- For each transaction in your proposal, you'll need its transaction hash.
- Under "Read Contract," locate
getTransactionHash
. For each transaction, input the relevant details. Use_operation
0
for a simplecall
, or1
for a delegate call (most normal operations use just acall
). Start withnonce
0
, increasing by1
for each subsequent transaction within a proposal. Reset to0
for each unique proposals. Click "Run Query" to obtain your transaction hash. - With all transaction hashes ready, click "Write Contract."
- Find
addProposal
, input yourproposalId
and an array of your transaction hashes in the correct order. - Click "+ Add this transaction," then "Bundle Transactions." Your transaction is now assembled. Click "Submit Transaction" and "Execute" to submit it on-chain.
- After your Snapshot proposal voting ends, you can either tip Telliot data reporters or submit the data yourself to get your vote results on-chain.
- Use the QueryId Station tool to generate
queryId
andqueryData
. Select "Custom," input "Snapshot" as thetype
, and add your SnapshotproposalId
. - If submitting results yourself, note that the submission is an ABI-encoded boolean. Submit
0x0000000000000000000000000000000000000000000000000000000000000001
for a passed proposal, or0x0000000000000000000000000000000000000000000000000000000000000000
otherwise. - Once data is submitted on-chain and the Tellor Zodiac module's
cooldown
period has passed, you can execute your proposal. - In the Zodiac frontend, go to "Write Contract" and choose "executeProposalWithIndex."
- Submit each transaction in the correct order, incrementing
_txIndex
by1
for each transaction, starting from0
. - After inputting all transactions, proceed to "bundle transactions," "Submit Transactions," and finally "Execute" to execute your transactions on-chain.
Your proposed transactions should now be successfully executed.
The contracts have been developed with Solidity 0.8.0 in mind. This version of Solidity made all arithmetic checked by default, therefore eliminating the need for explicit overflow or underflow (or other arithmetic) checks.
All contracts are WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.