✨Works out of the box guarantee. If you face any issue at all, hit us up on Telegram and we will write the integration for you.
logoReclaim Protocol Docs
Advance optionsjs-injections

Large Payload

Handling Large Payloads in Providers

Adding Large Payload as Public Data to the Proof Object

In the previous example, we saw how we can enable programmatic navigation. Now, let's explore how we can add large payloads as public data to the proof object.

Wait, What is Public Data?

You might be wondering, "What exactly is public data?" Well, here's the context:

Zero-knowledge proofs (ZKPs) come with certain limitations. These proofs are compute-intensive operations, and in many cases, they are executed directly on the user's device like a phone. There are no Reclaim servers in between the process. The phone has limited memory and cannot handle processing large amounts of data all at once.

This is where public data comes to the rescue.

Use Case: Large Payload Example

Let's say you are working with a large response, such as Swiggy order details. If you try to include all that data in the proof, the user might have to wait for several minutes just for the proof to generate. Instead of including the entire payload, you can verify one specific piece of data and store the rest as public data.

The flow would look like this:

  • You would verify a small piece of information, such as the order ID or the total amount of a specific order.
  • The rest of the data like the full order history would be added to the public parameters of the proof. While the proof only contains a verified subset, you can still be confident that the entire payload originates from the correct source.

In other words, the proof could verify a particular order's details (e.g., order ID, total price), but the full order history would be publicly available data. We will also have an attestation to confirm that the source of the data (in this case, Swiggy's API) is legitimate and trustworthy.

Example Code :

Prerequisites

Before proceeding, it's assumed that you have some experience with JavaScript DOM manipulation or making API calls. If you're unfamiliar with these concepts, it's recommended to first familiarize yourself with the basics of interacting with web pages using JavaScript.


Step 1: Fetching Order Details in the Background

There are two options for fetching order data:

  1. From DOM Elements
    If the order details are already available in the page's HTML, you can extract them using DOM manipulation techniques. However, this method is less reliable because the HTML structure might change frequently.

  2. From an Internal API
    A more reliable approach is to fetch the order details using an internal API that returns the order data. API responses are usually more stable than the structure of HTML elements.

Why Use API Calls?

  • Stability: The API response structure is less likely to change, ensuring your code remains functional over time.
  • Efficiency: APIs provide structured data, making it easier to parse and use compared to DOM manipulation.

The snippet below shows how to fetch Swiggy order details using an API call:

async function fetchOrderDetails() {
  try {
    // Swiggy's internal API (note: token or user ID requirements may apply)
    const response = await fetch('https://www.swiggy.com/dapi/order/all?order_id=', {
      headers: {
        __fetch_req__: 'true',
        accept: '*/*',
        'accept-language': 'en-GB,en;q=0.5',
        'content-type': 'application/json',
        'if-none-match': 'W/"1219b-rbUuzLmo540FSk8g0KzJG+MnMEs"',
        priority: 'u=1, i',
        'sec-ch-ua': '"Chromium";v="130", "Brave";v="130", "Not?A_Brand";v="99"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"macOS"',
        'sec-fetch-dest': 'empty',
        'sec-fetch-mode': 'cors',
        'sec-fetch-site': 'same-origin',
        'sec-gpc': '1',
      },
      referrer: 'https://www.swiggy.com/my-account',
      method: 'GET',
      mode: 'cors',
      credentials: 'include', // Important
    });
 
    const orders = await response.json();
    return orders;
  } catch (error) {
    console.error('Error fetching order details:', error);
  }
}

Step 2: Adding Public Data to the Proof Object

After fetching the order details, you need to add this data to the proof object and then navigate to the proof generation page.

function navigateToProofPage(orderData) {
  // Inject order data as public data
  window.flutter_inappwebview.callHandler('publicData', JSON.stringify(orderData));
 
  // Mark JS injection as completed
  window.reclaimFetchInjected = true;
 
  // Navigate to the proof generation page
  window.location.href = 'https://www.swiggy.com/my-account';
}
 
// Main function to control the process
async function handleProofGeneration() {
  // Check if the injection has already occurred
  if (window.reclaimFetchInjected) {
    console.log('JS already injected, skipping.');
    return;
  }
 
  showModal(); // Show the loading modal while fetching data
 
  const orderData = await fetchOrderDetails();
  if (orderData) {
    navigateToProofPage(orderData);
  }
}
 
// Run the function periodically (every 3 seconds)
setInterval(handleProofGeneration, 3000);

To include the fetched order data as public data in the proof object, you can use the window.flutter_inappwebview.callHandler() function. This method allows you to send the data to the native layer of the app for processing.

*// Assuming 'orderData' contains the order details fetched in Step 1*

window.flutter_inappwebview.callHandler('publicData', JSON.stringify(orderData));

publicData - is the keyword

Navigating to the Proof Generation Page

Now, you need to navigate to the page where the proof will actually be generated. In the case of Swiggy, the order data is available on the https://www.swiggy.com/my-account page.

window.location.href = 'https://www.swiggy.com/my-account';

Why navigate to a different page?

Reclaim operates based on response matching. When you are working with proof generation, the response from the target page (in this case, the Swiggy account page) must match the specific key pointers you've defined for the provider.

For instance, when generating the proof for Swiggy order details, you need to navigate to the my-account page because this is where the actual order data resides. The API or DOM response from that page will be compared with the pointers you've defined during the provider setup (e.g., order ID, total amount). Only if the response matches the defined pointers, the proof generation will be triggered.

3- Showing the Loading Modal (Optional) This is for the better UX.

When the script is running, you may want to show a loading modal to inform the user that data is being fetched and processed. Here's the function to show a loading modal:

function showModal() {
  let modal = document.createElement('div');
  modal.id = 'proofGenerationModal';
  modal.style.display = 'none';
  modal.style.position = 'fixed';
  modal.style.zIndex = '1';
  modal.style.paddingTop = '100px';
  modal.style.left = '0';
  modal.style.top = '0';
  modal.style.width = '100%';
  modal.style.height = '100%';
  modal.style.overflow = 'auto';
  modal.style.backgroundColor = 'rgba(0,0,0,0.4)';
  modal.innerHTML = `
        <div style="background-color: #000; color: #fff; margin: auto; padding: 20px; border: 1px solid #888; width: 80%; text-align: center;">
            <h3 style="padding-bottom: 20px;">Fetching data</h3>
            <p>Please wait</p>
            <div style="margin: 20px auto; width: 20px; height: 20px; border: 3px solid #fff; border-top: 3px solid #888; border-radius: 50%; animation: spin 1s linear infinite;"></div>
        </div>
        <style>
            @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
        </style>
    `;
  document.body.appendChild(modal);
  document.getElementById('proofGenerationModal').style.display = 'block';
}

Summary:

Fetching Order Data:

  • The fetchOrderDetails() function fetches the order data from the Swiggy API. You can adapt this for any other API or service as needed.

Loading Modal:

  • The showModal() function creates and displays a loading modal to inform users that data is being processed.

Injecting Data:

  • The navigateToProofPage() function injects the fetched order data into the proof generation process and navigates to the page where the proof is generated.

JS Injection Tracking:

  • The window.reclaimFetchInjected flag ensures that the JS injection only occurs once. This flag is set to true after the first injection to prevent redundant injections during subsequent checks.

Full Code:

// Function to fetch order details (can be adapted for other APIs)
async function fetchOrderDetails() {
  try {
    const response = await fetch('https://www.swiggy.com/dapi/order/all?order_id=', {
      headers: {
        __fetch_req__: 'true',
        accept: '*/*',
        'accept-language': 'en-GB,en;q=0.5',
        'content-type': 'application/json',
        'if-none-match': 'W/"1219b-rbUuzLmo540FSk8g0KzJG+MnMEs"',
        priority: 'u=1, i',
        'sec-ch-ua': '"Chromium";v="130", "Brave";v="130", "Not?A_Brand";v="99"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"macOS"',
        'sec-fetch-dest': 'empty',
        'sec-fetch-mode': 'cors',
        'sec-fetch-site': 'same-origin',
        'sec-gpc': '1',
      },
      referrer: 'https://www.swiggy.com/my-account',
      method: 'GET',
      mode: 'cors',
      credentials: 'include',
    });
    const orders = await response.json();
    return orders;
  } catch (error) {
    console.error('Error fetching order details:', error);
  }
}
 
// Function to show loading modal
function showModal() {
  let modal = document.createElement('div');
  modal.id = 'proofGenerationModal';
  modal.style.display = 'none';
  modal.style.position = 'fixed';
  modal.style.zIndex = '1';
  modal.style.paddingTop = '100px';
  modal.style.left = '0';
  modal.style.top = '0';
  modal.style.width = '100%';
  modal.style.height = '100%';
  modal.style.overflow = 'auto';
  modal.style.backgroundColor = 'rgba(0,0,0,0.4)';
  modal.innerHTML = `
        <div style="background-color: #000; color: #fff; margin: auto; padding: 20px; border: 1px solid #888; width: 80%; text-align: center;">
            <h3 style="padding-bottom: 20px;">Fetching data</h3>
            <p>Please wait</p>
            <div style="margin: 20px auto; width: 20px; height: 20px; border: 3px solid #fff; border-top: 3px solid #888; border-radius: 50%; animation: spin 1s linear infinite;"></div>
        </div>
        <style>
            @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
        </style>
    `;
  document.body.appendChild(modal);
  document.getElementById('proofGenerationModal').style.display = 'block';
}
 
// Function to navigate to the proof generation page after data is ready
function navigateToProofPage(orderData) {
  window.flutter_inappwebview.callHandler('publicData', JSON.stringify(orderData)); // orderData is from fetchOrderDetails
  window.reclaimFetchInjected = true; // set to true to prevent unnecessary calls
  window.location.href = 'https://www.swiggy.com/my-account';
}
 
// Main function to handle the entire flow
async function handleProofGeneration() {
  // Check if JS injection has already occurred
  if (window.reclaimFetchInjected) {
    console.log('JS already injected, skipping.');
    return; // Prevent multiple injections
  }
 
  showModal(); // Show loading modal while fetching data
  const orderData = await fetchOrderDetails(); // Fetch order data
  if (orderData) {
    navigateToProofPage(orderData); // Pass the data and navigate to proof generation page
  }
}
 
// Run the function periodically
setInterval(handleProofGeneration, 5000); // Check every 5 seconds

Proof Structure

————————-

{
    "reclaimProofRequestConfig": "{
        \"applicationId\": \"<APPLICATION_ID>\",
        \"providerId\": \"<PROVIDER_ID>\",
        \"sessionId\": \"<SESSION_ID>\",
        \"context\": {
            \"contextAddress\": \"<CONTEXT_ADDRESS>\",
            \"contextMessage\": \"<CONTEXT_MESSAGE>\"
        },
        \"publicData\": \"<Data>\",  // This is where all of the data is injected
        \"requestedProof\": {
            \"url\": \"<PROOF_URL>\",
            \"parameters\": {
                \"<PARAM1>\": \"\",
                \"<PARAM2>\": \"\"
            }
        },
        \"appCallbackUrl\": \"<CALLBACK_URL>\",
        \"signature\": \"<SIGNATURE>\",
        \"timeStamp\": \"<TIMESTAMP>\"
    }"
}

Summary:

  • Public Data is Not a Hack: It is meant to deliver public information, extracted directly from the webpage, that does not require the stringent verification process of the core proof.
  • Keep Verification Lean: Only send critical elements into the zero-knowledge proof, while the bulk of the data is passed as public data.
  • Improved Performance: By separating public data from the verification-relevant data, devices with limited resources (like mobile phones) can operate more efficiently.

For more production examples, please visit our GitHub repository.


On this page