Snapshot
This query returns the binary proposal result for a given proposal id (an IPFS hash for a certain proposal) coming from Snapshot. See https://snapshot.org/#/ for reference.
The Snapshot
query has one parameter, which specifies the requested data.
- proposalId (string): ID of the proposal.
The proposalId
should be a valid proposal on Snapshot.
- transactionsHash (bytes32): Hash of transactions hashes array.
The transactionsHash
should be generated by hashing each proposed transaction, putting each transaction hash into an array, and then hashing the array.
- moduleAddress (address): Address of the module which will execute the proposal.
The moduleAddress
determines which module the proposal is associated with.
The query response will consist of a boolean value in the following format:
abi_type
: boolpacked
: false
Query Descriptor:
{
"type": "Snapshot",
"inputs": [
{
"type": "string",
"name": "proposalId"
},
{
"type": "bytes32",
"name": "transactionsHash"
},
{
"type": "address",
"name": "moduleAddress"
}
],
"outputs": [
{
"type": "bool",
"packed": false
}
]
}
queryData: Generating the queryData is somewhat complex. The example below shows how to generate the query data for a proposed token transfer transaction.
contract SnapshotData {
enum Operation {Call, Delegatecall}
// keccak256(
// "Transaction(address to,uint256 value,bytes data,uint8 operation,uint256 nonce)"
// );
bytes32 public constant TRANSACTION_TYPEHASH =
0x72e9670a7ee00f5fbf1049b8c38e3f22fab7e9b85029e85cf9412f17fdd5c2ad;
// keccak256(
// "EIP712Domain(uint256 chainId,address verifyingContract)"
// );
bytes32 public constant DOMAIN_SEPARATOR_TYPEHASH =
0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;
/**
* @dev Generates the data for the module transaction hash (required for signing)
* @param _to Target of the transaction that should be executed
* @param _value Wei value of the transaction that should be executed
* @param _data Data of the transaction that should be executed
* @param _operation Operation (Call or Delegatecall) of the transaction that should be executed
* @param _nonce Nonce of the transaction that should be executed
*/
function generateTransactionHashData(
address _to,
uint256 _value,
bytes memory _data,
Operation _operation,
uint256 _nonce
) internal view returns (bytes memory) {
uint256 _chainId = getChainId();
// "this" is the tellor zodiac module contract address
// "_chainId" is the chain where the tx will be executed
bytes32 _domainSeparator = keccak256(
abi.encode(DOMAIN_SEPARATOR_TYPEHASH, _chainId, this)
);
bytes32 _transactionSubHash = keccak256(
abi.encode(
TRANSACTION_TYPEHASH,
_to,
_value,
keccak256(_data),
_operation,
_nonce
)
);
return
abi.encodePacked(
bytes1(0x19),
bytes1(0x01),
_domainSeparator,
_transactionSubHash
);
}
/**
* @dev Generates the hash for the module transaction
* @param _to Target of the transaction
* @param _value Wei value of the transaction
* @param _data Data of the transaction
* @param _operation Operation (Call or Delegatecall) of the transaction
* @param _nonce Nonce of the transaction
*/
function getTransactionHash(
address _to,
uint256 _value,
bytes memory _data,
Operation _operation,
uint256 _nonce
) public view returns (bytes32) {
return
keccak256(
generateTransactionHashData(
_to,
_value,
_data,
_operation,
_nonce
)
);
}
/**
* @dev Returns the chain id used by this contract.
*/
function getChainId() public view returns (uint256) {
uint256 _id;
assembly {
_id := chainid()
}
return _id;
}
// generates tx calldata for token transfer
function getTokenTransferCalldata(address _to, uint256 _amount) public pure returns(bytes memory) {
return abi.encodeWithSignature("transfer(address,uint256)", _to, _amount);
}
function getQueryData() public view returns(bytes memory _queryData) {
address _token = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
address _tokenRecipient = 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db;
address _module = 0x17F6AD8Ef982297579C203069C1DbfFE4348c372;
string memory _proposalId = "bafabcd3";
uint256 _tokenAmount = 10e18;
uint256 _etherAmount = 0;
Operation _operation = Operation.Call;
uint256 _nonce = 0;
bytes memory _txCalldata = getTokenTransferCalldata(_tokenRecipient, _tokenAmount);
bytes32 _txHash = getTransactionHash(_token, _etherAmount, _txCalldata, _operation, _nonce);
bytes32 _superHash = keccak256(abi.encode([_txHash]));
_queryData = abi.encode("Snapshot", abi.encode(_proposalId, _superHash, _module));
}
}
0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008536e617073686f7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000006013ae16d95d3835064a64b74a00f6efb964a1cb5292836feaec96d3ab1d69137a00000000000000000000000017f6ad8ef982297579c203069c1dbffe4348c37200000000000000000000000000000000000000000000000000000000000000086261666162636433000000000000000000000000000000000000000000000000
queryID:
keccak256(_queryData)
0x513a7b592992c0e5576fb3edbdeac505ea2337deb56af34c80b3361932af7190
A value of true
would be submitted on-chain using the following bytes:
0x0000000000000000000000000000000000000000000000000000000000000001
- It is the reporters responsibility to return the correct result of a proposal, if a proposal succeeds a value of true is expected, if a proposal doesn't pass a value of false is submitted.
In a "Basic voting" snapshot proposal with 10 000 yes votes and 2 000 no votes, assuming quorum was reached, a true
value is expected to be returned to show that the proposal succeeded.