Clique Docs
  • What Is Clique
    • TEE Network
    • Compute Coordination Network
  • Build with Clique
    • Clique Application Structure
    • Clique CLI
      • Installation
      • Develop Task
      • Build Task
      • Test Task
      • Deploy Task
    • Clique Client SDK
    • Smart Contract SDK
      • Smart Contract Integration
      • Clique Official Tasks
  • References
    • Clique Manifest
    • Clique Query
    • Verification
  • Sample Task Tutorials
    • Data Attestation
    • Social Verification
      • Github
      • Twitter
    • Making Arbitrary TLS Calls (TLS Oracle)
    • Custom Executor
  • Toolchain
    • Clique Pipelines SDK
    • Clique Attestation SDK
      • Attestation Protocols
      • Reading Attestations On-chain
      • Reading Attestations Off-Chain
      • What are Attestors ?
        • Data Sources
    • Clique Browser Extension
  • FAQ
  • Glossaries
  • Socials
Powered by GitBook
On this page
  • clique_httpsRequest
  • Make TLS Calls from Smart Contracts
  • Make TLS Calls from Client SDK
  • Make TLS Calls through Schema Task
  1. Sample Task Tutorials

Making Arbitrary TLS Calls (TLS Oracle)

Clique supports clients to make arbitrary TLS calls from smart contracts in a verifiable format. For generic TLS calls, we have provided the generic clique_httpsRequest Built-In task. Users can create queries for the clique_httpsRequest task to obtain the results of TLS calls. Users can also create more complex tasks of Schema type to utilize the clique_httpsRequest task.

clique_httpsRequest

Here is the manifest file for the clique_httpsRequest task:

spec-version = "1"
name = "clique_httpsRequest"
type = "BuiltIn"

proof-type = ["TEE"]

[types.Transformation]
from = { type = "string", description = "json pointer to field in response" }
soltype = { type = "string", description = "solidity type" }

[input]
url = { type = "string", description = "Request url" }
encoding = { type = "Transformation[]", description = "encoding format" }

[output]
response = { type = "bytes", description = "ABI encoded" }

clique_httpsRequest is a built-in task, which means users can directly use this task within the Clique Network without the need to publish it additionally.

This task has two output parameters:

  • url: The URL to be accessed for this TLS call. The URL needs to return parseable results in JSON format.

  • encoding: Indicates how to extract data from the returned JSON result. Here we use an array of custom types (Transformation) as the input parameter. The Transformation custom type contains two fields: from is a JSON pointer for extracting data from JSON, and soltype is the Solidity type into which the extracted data should be encoded.

This task has only one return value: response. The response is data encoded in Solidity ABI format, with the encoding format specified by the input parameter encoding. After obtaining the result of the TLS call, the smart contract can decode the data using ABI decoding to retrieve the information.

Make TLS Calls from Smart Contracts

This URL will return JSON data in the following format:

[
    {
        "id": 1,
        "name": "Leanne Graham",
        "username": "Bret",
        "email": "Sincere@april.biz",
        "address": {
            "street": "Kulas Light",
            "suite": "Apt. 556",
            "city": "Gwenborough",
            "zipcode": "92998-3874",
            "geo": {
                "lat": "-37.3159",
                "lng": "81.1496"
            }
        },
        "phone": "1-770-736-8031 x56442",
        "website": "hildegard.org",
        "company": {
            "name": "Romaguera-Crona",
            "catchPhrase": "Multi-layered client-server neural-net",
            "bs": "harness real-time e-markets"
        }
    },
    ...
]

In the following example, we will use TLS Call to extract id, name, lat, and the entire JSON array from the returned JSON result.

pragma solidity ^0.8.22;

import {ICliqueTaskManager} from "../src/ICliqueTaskManager.sol";

struct Transformation {
    string from;
    string soltype;
}

struct Params {
    string url;
    Transformation[] encoding;
}

struct Response {
    bytes response;
}

struct Result {
    uint32 id;
    string name;
    string geoLat;
    string[] array;
}

contract HttpsRequest {
    address public immutable _manager;

    event CallbackInvoked(Result);

    constructor(address manager) {
        _manager = manager;
    }

    function callback(bytes calldata _response) external {
        Response memory response = abi.decode(_response, (Response));
        Result memory result = abi.decode(response.response, (Result));
        emit CallbackInvoked(result);
    }

    function run(uint32 id) public {
        Transformation[] memory transformations = new Transformation[](4);
        transformations[0] = Transformation({from: "/0/id", soltype: "uint32"});
        transformations[1] = Transformation({from: "/0/name", soltype: "string"});
        transformations[2] = Transformation({from: "/0/address/geo/lat", soltype: "string"});
        transformations[3] = Transformation({from: "", soltype: "string[]"});

        Params memory params = Params({
            url: "https://jsonplaceholder.typicode.com/users",
            encoding: transformations
        });

        ICliqueTaskManager.Task memory task = ICliqueTaskManager.Task(
            id,
            "clique_httpsRequest",
            abi.encode(params)
        );
        ICliqueTaskManager(_manager).createNewTask{value: 0.05 ether}(
            abi.encode(task),
            this.callback.selector
        );
    }
}

Let's break down the example.

import {ICliqueTaskManager} from "../src/ICliqueTaskManager.sol";

Import the Clique Contract SDK here.

struct Transformation {
    string from;
    string soltype;
}

Define the custom typeTransformation for the clique_httpsRequest task. The name of the structure is not important, but the content of the structure must be consistent with the custom type inclique_httpsRequest task.

The names of the other structures to be defined next are not important; users can define names as they wish.

struct Params {
    string url;
    Transformation[] encoding;
}

Define the input parameters according to the input type of the clique_httpsRequest task.

struct Response {
    bytes response;
}

Define the output parameters according to the output type of the clique_httpsRequest task.

struct Result {
    uint32 id;
    string name;
    string geoLat;
    string[] array;
}

Define the decoded result of the TLS call. The clique_httpsRequest task will return the encoded result, which will be decoded according to this structure.

Transformation[] memory transformations = new Transformation[](4);
transformations[0] = Transformation({from: "/0/id", soltype: "uint32"});
transformations[1] = Transformation({from: "/0/name", soltype: "string"});
transformations[2] = Transformation({from: "/0/address/geo/lat", soltype: "string"});
transformations[3] = Transformation({from: "", soltype: "string[]"});

Create the Transformation structure needed in the input parameters, using JSON Pointer to specify how to extract data from the JSON result, and determine how to encode the extracted data. The result data will be encoded in the order specified by the Transformation array.

Params memory params = Params({
    url: "https://jsonplaceholder.typicode.com/users",
    encoding: transformations
});

Construct the input parameters.

ICliqueTaskManager.Task memory task = ICliqueTaskManager.Task(
    id,
    "clique_httpsRequest",
    abi.encode(params)
);

Construct the clique_httpsRequest query.

Each time a query is created, a different ID needs to be specified. If the content of the query is exactly the same, Clique Network will not create a new query.

ICliqueTaskManager(_manager).createNewTask{value: 0.05 ether}(
    abi.encode(task),
    this.callback.selector
);

Use the Clique Contract SDK to create a query and wait for the callback function to execute.

function callback(bytes calldata _response) external {
    Response memory response = abi.decode(_response, (Response));
    Result memory result = abi.decode(response.response, (Result));
    emit CallbackInvoked(result);
}

Define the callback function and decode the result of the TLS call within the callback function.

Make TLS Calls from Client SDK

Although the primary use case for TLS Calls is in smart contracts, it is also supported off-chain. Users can use the Clique Client SDK to call the clique_httpsRequest task.

For example, use our Rust SDK:

Add this dependency to your Cargo.toml

clique-client-sdk = { git = "https://github.com/CliqueOfficial/clique-protocol-sdk" }
serde_json = { version = "1.0", features = ["preserve_order"] }
tokio = { version = "1.38.0", features = ["full"] }
use clique_client_sdk::CliqueClient;
use serde_json::json;

#[tokio::main]
async fn main() {
    let endpoint = "https://localhost:8000";
    let client = CliqueClient::new(endpoint).unwrap();

    let id = 1;
    let url = "https://jsonplaceholder.typicode.com/users";
    let encoding = json!([
        {"from": "/0/id", "soltype": "int16"},
        {"from": "/0/name", "soltype": "string"},
        {"from": "/0/address/geo/lat", "soltype": "string"}
    ]);
    let json_query = json!({
        "id": id,
        "method": "clique_httpsRequest",
        "params": {"url": url, "encoding": encoding },
        "input_types": {"url": "string", "encoding": "Transformation[]"},
        "custom_types": {"Transformation": {"from": "string", "soltype": "string"}}
    });
    let result = client.run_query(json_query).await.unwrap();
}

Make TLS Calls through Schema Task

In addition to directly using the clique_httpsRequest task, users can also customize their own Schema tasks and indirectly use clique_httpsRequest within these Schema tasks to construct more complex queries.

Here is a simple example of a Schema task's manifest file. After defining the manifest file, users need to first publish it to the Clique Network using Clique CLI, and then create the corresponding query to use it.

specVersion = "1"
name = "yourOrganization_customRequest"
type = "Schema"

proof-type = ["TEE"]

[types.Transformation]
from = { type = "string", description = "json pointer to field in response" }
soltype = { type = "string", description = "solidity type" }

[input]
url = { type = "string", description = "Request url" }
encoding = { type = "Transformation[]", description = "encoding format" }

[output]
response = { ref = "$tasks.clique_httpsRequest.response" }

[[tasks]]
name = "clique_httpsRequest"
proof-preference = "TEE"
[tasks.input]
url = "$input.url"
encoding = "$input.encoding"

PreviousTwitterNextCustom Executor

Last updated 5 months ago

Here is a smart contract example, initiating a TLS call to and extracting data.

https://jsonplaceholder.typicode.com/users