How to send a pre-signed query request using @dfinity/agent?

Hi everyone! :waving_hand:

I have a canister that prepares and signs a query request, and this request needs to be sent to the IC network from the browser.

The request is passed into the browser as a Uint8Array | number[], and I want to send it using JavaScript with the @dfinity/agent package.

Question:

Is there a convenient way to send such a pre-signed query request to the Internet Computer using @dfinity/agent?

I’ve looked through the documentation but couldn’t find a clear way to send a “raw signed request”. Essentially, I’d like to reuse the code from the internal _HttpAgent_requestAndRetryQuery function, but it’s private and not directly accessible. Has anyone dealt with a similar case or knows how to handle this correctly using @dfinity/agent?


Additional context:

• The request is signed by a Rust canister/server.

• No signing is needed on the client side.

• The only task is to send the already signed query from the browser to the IC.

I’d really appreciate any advice, code samples, or pointers! :folded_hands:

@kpeacock @sea-snake

This is something that Oisy has done!

You can use the HttpAgent.query and await the response - the retry and polling won’t enter into the issue in the majority of cases

The HttpAgent.query method contains a lot of logic that is already handled by the backend canister.

On the client side, I already have a fully prepared and signed envelope ready to send.

Here’s what the backend canister does:
1. Prepares the QueryContent::QueryRequest.
2. Calculates the request_id.
3. Constructs the message_hash.
4. Signs it using the sign_with_ecdsa method.
5. Serializes the envelope using CBOR.

However, HttpAgent.query creates its own QueryRequest, whereas I need to send the pre-signed request from the backend.

@kpeacock any ideas?

Please tag someone who might be able to help.

Thank you.

If you already have everything, including a pre-calculated request_id, signature, and cbor-encoded body, all that’s left is a fetch request to https://icp-api.io/api/v2/canister/${canisterIdtoString()}/query, right?

It would look something like this:

await fetch(`https://icp-api.io/api/v2/canister/${canisterIdtoString()}/query`, {
  request: {
      method: 'POST',
      headers: { 'Content-Type': 'application/cbor' }
  },
  endpoint: 'read',
  body
});
1 Like