Skip to content

Latest commit

 

History

History
207 lines (167 loc) · 6.84 KB

Snapshot.md

File metadata and controls

207 lines (167 loc) · 6.84 KB

Snapshot Specific Feeds

Query Name

  • Snapshot

Query Description

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.

Query Parameters

The Snapshot query has one parameter, which specifies the requested data.

  1. proposalId (string): ID of the proposal.

The proposalId should be a valid proposal on Snapshot.

  1. 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.

  1. moduleAddress (address): Address of the module which will execute the proposal.

The moduleAddress determines which module the proposal is associated with.

Response Type

The query response will consist of a boolean value in the following format:

  • abi_type: bool
  • packed: 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

Encoding/Decoding

A value of true would be submitted on-chain using the following bytes:

0x0000000000000000000000000000000000000000000000000000000000000001

Dispute Considerations

  • 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.

Example

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.