Source to get .did file from any canister

I’m deploying some service outside of Dfinity canister. Any with JS agent and did file I can make few interesting thing with app outside of canister. For every canister I used icscan to get the did file but this morning I found that there is some canister like Openchat’s canister cannot get the did file from icscan.

So my question is what is mechanism to public the did file in icscan and is that any way to get the did file with these private canisters?

If canisters expose their .did file then the convention is to do it in the candid:service metadata section. You can fetch that section with dfx canister --ic metadata <canister id> candid:service

3 Likes

How can we do the same programatically? can we fetch the candid of canister using javascript?

Yes, there’s a utility method in agent-js to fetch the candid:

import { fetchCandid } from "@dfinity/agent";

const agent = new HttpAgent()
const did = await fetchCandid(CANISTER_ID, agent);

Keep in mind this will be a string containing the did file contents. If you want to use this to e.g. create an actor, you’d still need to convert this into js/ts definition files.

1 Like

to convert did into js/ts i found, we can get it from this canister:

import { IDL } from "@dfinity/candid";
import { Actor, HttpAgent } from "@dfinity/agent";

export const candidToJS = async (candid_source: string) => {
  // call didjs canister
  const didjs_interface: IDL.InterfaceFactory = ({ IDL }) =>
    IDL.Service({
      did_to_js: IDL.Func([IDL.Text], [IDL.Opt(IDL.Text)], ["query"]),
    });

  const candidCanister = `a4gq6-oaaaa-aaaab-qaa4q-cai`;

  const agent = new HttpAgent({ host: "https://icp-api.io" });

  const didjs = Actor.createActor(didjs_interface, {
    agent,
    canisterId: candidCanister,
  });
  const js: any = await didjs.did_to_js(candid_source);
  if (Array.isArray(js) && js.length === 0) {
    return undefined;
  }
  return js[0];
};

do we have any other offline solution? i mean where we generate didtojs on our end and don’t have to make any call to other service or canister.

Running the following in WASM is the current solution I’m working with: candid/rust/candid_parser at master · dfinity/candid · GitHub

1 Like

I would suggest using @ic-reactor, a library I’m currently developing. You can easily use the CandidAdapter feature to get the candid definition as an idlFactory, which can be used directly to create an actor:

// adapter.ts
import { createAgentManager, createCandidAdapter } from "@ic-reactor/core";

export const agentManager = createAgentManager({ withProcessEnv: true });

export const adapter = createCandidAdapter({ agentManager });

export async function getCandidDefinition(canisterId: string) {
  return adapter.getCandidDefinition(canisterId);
}

This approach is similar to the one used by candid-ui.

Yes, there is also an offline solution using the wasm mentioned by @sea-snake. You just need to install:

npm install @ic-reactor/parser

Then, initialize the wasm parser after creating the CandidAdapter:

adapter.initializeParser();

Additionally, if you are using React, you might want to try @ic-reactor/react. It has a built-in adapting actor feature that only requires you to specify the canisterId to interact with it!

I have developed this library and it is used extensively in the creation of B3Forge. Please also give a shot to the B3Forge/playground. As you can see, it does not make a call to convert candid into JavaScript.

2 Likes

ok i’ll check these out. thanks for the help.

1 Like