### Quick Start: Create agent and call canister with @icp-sdk/core Source: https://github.com/dfinity/icp-js-core/blob/main/README.md Quick Start example for using the @icp-sdk/core package. Creates an Ed25519KeyIdentity, a Principal from a canister ID, and an HttpAgent connected to the ICP mainnet host. Sends an update call to the canister with a 'greet' method and a text argument encoded via IDL. ```typescript import { HttpAgent } from '@icp-sdk/core/agent'; import { Ed25519KeyIdentity } from '@icp-sdk/core/identity'; import { IDL } from '@icp-sdk/core/candid'; import { Principal } from '@icp-sdk/core/principal'; const identity = Ed25519KeyIdentity.generate(); const canisterId = Principal.fromText('uqqxf-5h777-77774-qaaaa-cai'); const agent = await HttpAgent.create({ host: 'https://icp-api.io', identity, }); // Send an update call to the canister await agent.call(canisterId, { methodName: 'greet', arg: IDL.encode([IDL.Text], ['world']), }); ``` -------------------------------- ### Install @icp-sdk/core package Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v4.md Install the new @icp-sdk/core package after removing the old @dfinity packages. ```shell npm i @icp-sdk/core ``` -------------------------------- ### Install @icp-sdk/core with npm Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/installation.mdx Use npm to install the @icp-sdk/core package. ```shell npm install @icp-sdk/core ``` -------------------------------- ### Install @dfinity/agent and peer dependencies Source: https://github.com/dfinity/icp-js-core/wiki/Getting-Started Installs the agent, Principal, and Candid packages. These are peer dependencies required for the agent to work. ```sh npm install --save @dfinity/agent @dfinity/principal @dfinity/candid ``` -------------------------------- ### Install @icp-sdk/core with bun Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/installation.mdx Use bun to add the @icp-sdk/core package. ```shell bun add @icp-sdk/core ``` -------------------------------- ### Node.js setup with polyfills and host Source: https://github.com/dfinity/icp-js-core/wiki/Getting-Started Sets global polyfills for crypto, TextEncoder, TextDecoder, and fetch, then initializes HttpAgent with a host. Required for Node.js applications. ```js // index.js global.crypto = require('@trust/webcrypto'); global.TextEncoder = require('text-encoding').TextEncoder; global.TextDecoder = require('text-encoding').TextDecoder; global.fetch = require('node-fetch'); ... const agent = new HttpAgent({ host: "https://ic0.app" }); ... ``` -------------------------------- ### Install Node.js polyfill packages Source: https://github.com/dfinity/icp-js-core/wiki/Getting-Started Installs @trust/webcrypto, text-encoding, and node-fetch as dev dependencies to polyfill global utilities required by the agent in Node.js. ```sh npm install --save-dev @trust/webcrypto text-encoding node-fetch ``` -------------------------------- ### Install @icp-sdk/core with pnpm Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/installation.mdx Use pnpm to add the @icp-sdk/core package. ```shell pnpm add @icp-sdk/core ``` -------------------------------- ### Install peer dependencies with pnpm Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v4.md When using pnpm, manually install the required peer dependencies for @icp-sdk/core. ```shell pnpm install @dfinity/agent @dfinity/candid @dfinity/identity @dfinity/identity-secp256k1 @dfinity/principal ``` -------------------------------- ### Install @icp-sdk/core with yarn Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/installation.mdx Use yarn to add the @icp-sdk/core package. ```shell yarn add @icp-sdk/core ``` -------------------------------- ### Minimal browser setup for HttpAgent and Actor Source: https://github.com/dfinity/icp-js-core/wiki/Getting-Started Imports Actor and HttpAgent, defines a Candid interface for a canister with a 'greet' method, and creates an actor. Assumes hosting on localhost or ic0.app. ```js // index.js import { Actor, HttpAgent } from "@dfinity/agent"; const canisterId = "rrkah-fqaaa-aaaaa-aaaaq-cai"; // Candid interface for a canister with one 'greet' method const idlFactory = ({ IDL }) => { return IDL.Service({ "greet" : IDL.Func([IDL.Text], [IDL.Text], []) }); }; // Initialize a HttpAgent, which handles low-level calls to the IC API const agent = new HttpAgent(); // Initialize an actor interface, which will make calls to methods defined in the idlFactory const actor = Actor.createActor(idlFactory, { agent, canisterId }); ``` -------------------------------- ### HttpAgent.createSync and HttpAgent.create with shouldSyncTime and shouldFetchRootKey Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md Examples showing synchronous and asynchronous agent construction with shouldSyncTime and shouldFetchRootKey options, highlighting when time sync occurs. ```typescript // When constructing the agent synchronously, the time is not synced until the first request is made const agent = HttpAgent.createSync({ shouldSyncTime: true, // shouldFetchRootKey: true, // even more relevant if you want to sync the root key as well }); agent.call(...); // the time is synced at this point, before the call is made ``` ```typescript // When constructing the agent asynchronously, the time is synced when the agent is created const agent = await HttpAgent.create({ shouldSyncTime: true, // shouldFetchRootKey: true, // if both flags are enabled, the agent creation will take longer }); agent.call(...); // the time is already synced at this point ``` -------------------------------- ### Install @icp-sdk/core latest version Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v5.md After removing the peer dependencies, run this command to upgrade @icp-sdk/core to the latest version. ```shell npm install @icp-sdk/core@latest ``` -------------------------------- ### Usage example for @icp-sdk/core Source: https://github.com/dfinity/icp-js-core/blob/main/packages/core/README.md Demonstrates importing HttpAgent, Ed25519KeyIdentity, IDL, and Principal from the package, creating an identity, principal, and agent, and calling a canister. Requires TypeScript moduleResolution 'node16' or later. ```ts // Importing the HttpAgent from the agent module import { HttpAgent } from '@icp-sdk/core/agent'; // Importing the Identity utility import { Ed25519KeyIdentity } from '@icp-sdk/core/identity'; // Importing the Candid utility import { IDL } from '@icp-sdk/core/candid'; // Importing the Principal utility import { Principal } from '@icp-sdk/core/principal'; // Create a new identity const identity = Ed25519KeyIdentity.generate(); // Create a Principal from a string const canisterId = Principal.fromText('uqqxf-5h777-77774-qaaaa-cai'); // Create an HttpAgent instance const agent = await HttpAgent.create({ host: 'https://icp-api.io', identity, }); // Call a canister const response = await agent.call(canisterId, { methodName: 'greet', arg: IDL.encode([IDL.Text], ['world']), }); console.log(response); ``` -------------------------------- ### Interact with a canister using HttpAgent Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/quick-start.mdx This example demonstrates how to interact with a canister directly using the HttpAgent class without an actor. ```typescript // Importing the HttpAgent from the agent module import { HttpAgent } from '@icp-sdk/core/agent'; import { Ed25519KeyIdentity } from '@icp-sdk/core/identity'; import { IDL } from '@icp-sdk/core/candid'; import { Principal } from '@icp-sdk/core/principal'; const identity = Ed25519KeyIdentity.generate(); // For a convenient way to get the canister ID, // see the https://js.icp.build/core/latest/canister-environment/ guide. const canisterId = Principal.fromText('uqqxf-5h777-77774-qaaaa-cai'); const agent = await HttpAgent.create({ host: 'https://icp-api.io', identity, }); // Send an update call to the canister await agent.call(canisterId, { methodName: 'greet', arg: IDL.encode([IDL.Text], ['world']), }); ``` -------------------------------- ### HttpAgent.create with shouldSyncTime option Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md Example of creating an HttpAgent asynchronously with the shouldSyncTime option enabled, which syncs the time when the agent is created. ```typescript const agent = await HttpAgent.create({ shouldSyncTime: true, }); ``` -------------------------------- ### Replace old imports with new imports Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v4.md Example showing how to replace an old import from @dfinity/agent with the new import from @icp-sdk/core/agent. The minus sign indicates the old line to remove, and the plus sign indicates the new line to add. ```ts - import { HttpAgent } from '@dfinity/agent'; + import { HttpAgent } from '@icp-sdk/core/agent'; ``` -------------------------------- ### Interact with a canister using an Actor Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/quick-start.mdx This example demonstrates the standard approach for interacting with canisters using an Actor. It includes the main application logic in index.ts and the structure of the auto-generated API file. ```typescript import { HttpAgent } from "@icp-sdk/core/agent"; import { Ed25519KeyIdentity } from "@icp-sdk/core/identity"; import { Principal } from "@icp-sdk/core/principal"; import { createActor } from "./api/hello-world"; // For a convenient way to get the canister ID, // see the https://js.icp.build/core/latest/canister-environment/ guide. const canisterId = Principal.fromText('uqqxf-5h777-77774-qaaaa-cai'); const identity = Ed25519KeyIdentity.generate(); const agent = await HttpAgent.create({ host: 'https://icp-api.io', identity, }); const actor = createActor(canisterId, { agent, }); const response = await actor.greet('world'); console.log(response); ``` ```typescript // This file is typically auto-generated by the @icp-sdk/bindgen package. // You should not write this file manually. import { Actor, HttpAgent, type HttpAgentOptions, type ActorConfig, type Agent, type ActorSubclass } from "@icp-sdk/core/agent"; import { idlFactory, type _SERVICE } from "./declarations/hello-world.did"; // ... omitted for brevity ... export class Hello_world implements hello_worldInterface { constructor(private actor: ActorSubclass<_SERVICE>){} async greet(arg0: string): Promise { const result = await this.actor.greet(arg0); return result; } } // ... omitted for brevity ... export function createActor(canisterId: string, options: CreateActorOptions = {}): Hello_world { // ... omitted for brevity ... return new Hello_world(actor); } ``` -------------------------------- ### Handling AgentError Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md Example of catching and inspecting the generic AgentError class properties. ```typescript try { // agent call } catch (e) { if (e instanceof AgentError) { console.error(e.message); if ( e.code instanceof CertifiedRejectErrorCode && // or e.cause.code e.kind === ErrorKindEnum.Trust // or e.cause.kind ) { // do something } } } ``` -------------------------------- ### Request subnet status with SubnetStatus.request Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v5.md Uses the SubnetStatus namespace to request subnet information from the IC public API. The request takes a subnetId, paths, and an agent; the result provides get() access to the requested paths. ```typescript import { SubnetStatus } from '@icp-sdk/core/agent'; const subnetId = Principal.fromText('jtdsg-3h6gi-hs7o5-z2soi-43w3z-soyl3-ajnp3-ekni5-sw553-5kw67-nqe'); const status = await SubnetStatus.request({ subnetId, paths: ['time', 'nodeKeys'], agent, }); const time = status.get('time'); const nodeKeys = status.get('nodeKeys'); console.log(time); console.log(nodeKeys); ``` -------------------------------- ### Run migration with npm Source: https://github.com/dfinity/icp-js-core/blob/main/packages/migrate/README.md Run the migration tool in your project directory using npm. ```shell npx @icp-sdk/core-migrate@latest ``` -------------------------------- ### Run migration with pnpm Source: https://github.com/dfinity/icp-js-core/blob/main/packages/migrate/README.md Run the migration tool in your project directory using pnpm. ```shell pnpm dlx @icp-sdk/core-migrate@latest ``` -------------------------------- ### Specify custom host for HttpAgent Source: https://github.com/dfinity/icp-js-core/wiki/Getting-Started Use this when hosting on your own domain or running in Node.js. The host must be specified to point to the Internet Computer. ```js const agent = new HttpAgent({ host: "https://ic0.app" }); ``` -------------------------------- ### Update HttpAgent shouldFetchRootKey behavior Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md The root key is now fetched on the first request for synchronous HttpAgent creation. Asynchronous creation behavior remains unchanged. ```typescript // When constructing the agent synchronously, the root key was fetched automatically in the background, // causing potential race conditions const agent = HttpAgent.createSync({ shouldFetchRootKey: true }); // or, even if deprecated, new HttpAgent({ shouldFetchRootKey: true }) agent.call(...); // we don't know if the root key was fetched or not at this point // When constructing the agent asynchronously, the root key was fetched directly const agent = await HttpAgent.create({ shouldFetchRootKey: true }); agent.call(...); // the root key has already been fetched at this point ``` ```typescript // When constructing the agent synchronously, the root key is not fetched until the first request is made const agent = HttpAgent.createSync({ shouldFetchRootKey: true }); // or, even if deprecated, new HttpAgent({ shouldFetchRootKey: true }) agent.call(...); // the root key is fetched at this point, before the call is made // When constructing the agent asynchronously, nothing changes const agent = await HttpAgent.create({ shouldFetchRootKey: true }); agent.call(...); // the root key has already been fetched at this point ``` -------------------------------- ### Call canister method greet Source: https://github.com/dfinity/icp-js-core/wiki/Getting-Started Calls the 'greet' method on the actor instance. Returns a promise that resolves to the response string. ```js actor.greet("New Dev"); // -> "Hello, New Dev!" ``` -------------------------------- ### Certificate.create Before Migration Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v5.md The previous implementation of Certificate.create using the canisterId option. ```typescript import { Certificate } from '@icp-sdk/core/agent'; const canisterId = Principal.fromText('uqqxf-5h777-77774-qaaaa-cai'); const certificate = await Certificate.create({ certificate: certBytes, rootKey: agent.rootKey, canisterId, }); ``` -------------------------------- ### Look up canister ranges with lookupCanisterRanges and decodeCanisterRanges Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v5.md Demonstrates lookupCanisterRanges and decodeCanisterRanges to extract canister ranges from a certificate tree. Requires a Certificate instance and an agent with rootKey. ```typescript import { lookupCanisterRanges, decodeCanisterRanges, } from '@icp-sdk/core/agent'; const canisterId = Principal.fromText('uqqxf-5h777-77774-qaaaa-cai'); const subnetId = Principal.fromText('jtdsg-3h6gi-hs7o5-z2soi-43w3z-soyl3-ajnp3-ekni5-sw553-5kw67-nqe'); const certificate = await Certificate.create({ certificate: certBytes, principal: { canisterId }, rootKey: agent.rootKey, }); const canisterRanges = lookupCanisterRanges({ subnetId, tree: certificate.tree, canisterId }); const ranges = decodeCanisterRanges(canisterRanges); console.log(ranges); ``` -------------------------------- ### Certificate.create After Migration Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v5.md The updated implementation of Certificate.create using the principal option, which supports both canisterId and subnetId. ```typescript import { Certificate } from '@icp-sdk/core/agent'; const canisterId = Principal.fromText('uqqxf-5h777-77774-qaaaa-cai'); const certificate = await Certificate.create({ certificate: certBytes, principal: { canisterId }, rootKey: agent.rootKey, }); // or const subnetId = Principal.fromText('jtdsg-3h6gi-hs7o5-z2soi-43w3z-soyl3-ajnp3-ekni5-sw553-5kw67-nqe'); const certificate = await Certificate.create({ certificate: certBytes, principal: { subnetId }, rootKey: agent.rootKey, }); ``` -------------------------------- ### Use HttpAgent subnet state methods Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v5.md Shows the new HttpAgent methods for subnet state: getSubnetIdFromCanister, readSubnetState, and syncTimeWithSubnet. Requires an HttpAgent instance created with HttpAgent.create(). ```typescript import { HttpAgent } from '@icp-sdk/core/agent'; const agent = await HttpAgent.create(); // Get the subnet ID for a canister const subnetId = await agent.getSubnetIdFromCanister(canisterId); // Read subnet state directly const subnetState = await agent.readSubnetState(subnetId, paths); // Sync time with a specific subnet await agent.syncTimeWithSubnet(subnetId); ``` -------------------------------- ### Configure Actor with Canister Environment Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/canister-environment.mdx Use the canister environment to dynamically configure an actor, avoiding the need to pass environment variables at build time. ```typescript import { getCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import { createActor } from "./backend/api/hello_world"; // generated by the https://js.icp.build/bindgen tool interface CanisterEnv { readonly "PUBLIC_CANISTER_ID:backend": string; } const canisterEnv = getCanisterEnv(); const canisterId = canisterEnv["PUBLIC_CANISTER_ID:backend"]; const helloWorldActor = createActor(canisterId, { agentOptions: { rootKey: !import.meta.env.DEV ? canisterEnv.IC_ROOT_KEY : undefined, shouldFetchRootKey: import.meta.env.DEV, }, }); // Now you can call the backend canister methods console.log(helloWorldActor.greet("World")); ``` -------------------------------- ### Configure Rollup/Vite externals for @icp-sdk/core submodules Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/library-development.mdx Configure Rollup or Vite to treat each @icp-sdk/core submodule as external and provide global names for UMD builds. Required for libraries depending on @icp-sdk/core to avoid bundling the core modules. ```javascript // rollup.config.js or vite.config.js export default { build: { rollupOptions: { external: [ '@icp-sdk/core/agent', '@icp-sdk/core/candid', '@icp-sdk/core/identity', '@icp-sdk/core/identity/secp256k1', '@icp-sdk/core/principal', ], output: { globals: { '@icp-sdk/core/agent': 'icp-sdk-core-agent', '@icp-sdk/core/candid': 'icp-sdk-core-candid', '@icp-sdk/core/identity': 'icp-sdk-core-identity', '@icp-sdk/core/identity/secp256k1': 'icp-sdk-core-identity-secp256k1', '@icp-sdk/core/principal': 'icp-sdk-core-principal', }, }, }, }, }; ``` -------------------------------- ### Manually update test mocks Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v4.md The migration CLI only updates imports; manual updates are required for other references such as test mocks. ```diff - vi.mock('@dfinity/agent', () => ({ + vi.mock('@icp-sdk/core/agent', () => ({ ... })); ``` -------------------------------- ### Retrieve Canister Environment with getCanisterEnv Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/canister-environment.mdx Use getCanisterEnv to load the canister environment from the ic_env cookie. This module is experimental. ```typescript import { getCanisterEnv } from "@icp-sdk/core/agent/canister-env"; const canisterEnv = getCanisterEnv(); console.log(getCanisterEnv.IC_ROOT_KEY); // served by default by the asset canister ``` -------------------------------- ### Refactoring Expiry class Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md Migration from the public Expiry constructor to static factory methods and JSON support. ```typescript import { Expiry } from '@dfinity/agent'; const fiveMinutesInMs = 5 * 60 * 1000; const expiry = new Expiry(fiveMinutesInMs); ``` ```typescript import { Expiry } from '@dfinity/agent'; // Create an expiry 5 minutes from now. const fiveMinutesInMs = 5 * 60 * 1000; const expiry = Expiry.fromDeltaInMilliseconds(fiveMinutesInMs); // You can also serialize and deserialize Expiry objects. const json = expiry.toJSON(); const expiryFromJson = Expiry.fromJSON(JSON.stringify(json)); ``` -------------------------------- ### Replace utility functions with @noble/hashes/utils Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md The fromHex, toHex, and concat functions are removed. Use bytesToHex, hexToBytes, and concatBytes from @noble/hashes/utils. ```typescript import { toHex, fromHex, concat } from '@dfinity/agent'; const hex = toHex(myUint8Array); const bytes = fromHex(myHexString); const combined = concat(buffer1, buffer2); ``` ```typescript import { bytesToHex, hexToBytes, concatBytes } from '@noble/hashes/utils'; const hex = bytesToHex(myUint8Array); const bytes = hexToBytes(myHexString); const combined = concatBytes(buffer1, buffer2); ``` -------------------------------- ### Update Cbor usage to @dfinity/cbor Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md The @dfinity/agent package now uses @dfinity/cbor. Note that Cbor.encode now returns a Uint8Array and Cbor.decode accepts a Uint8Array. ```typescript import { Cbor } from '@dfinity/agent'; const encoded: ArrayBuffer = Cbor.encode(myValue); const decoded: MyType = Cbor.decode(encoded); ``` ```typescript import { Cbor } from '@dfinity/agent'; const encoded: Uint8Array = Cbor.encode(myValue); // now returns Uint8Array const decoded = Cbor.decode(encoded); // now accepts Uint8Array ``` -------------------------------- ### Remove old @dfinity packages Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v4.md Remove the old @dfinity packages that are replaced by @icp-sdk/core. This command removes agent, candid, identity, identity-secp256k1, and principal packages. ```shell npm remove @dfinity/{agent,candid,identity,identity-secp256k1,principal} ``` -------------------------------- ### Configure moduleResolution in tsconfig.json Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/typescript.mdx Set the moduleResolution to node16, nodenext, or bundler in your tsconfig.json file to ensure compatibility with the @icp-sdk/core package. ```json { "compilerOptions": { "moduleResolution": "node16" } } ``` -------------------------------- ### Removing defaultAgent Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md Comparison of the deprecated getDefaultAgent approach versus the new HttpAgent instantiation. ```typescript import { getDefaultAgent } from '@dfinity/agent'; const agent = getDefaultAgent(); ``` ```typescript import { HttpAgent } from '@dfinity/agent'; const agent = await HttpAgent.create(); // or use the synchronous version `HttpAgent.createSync()` ``` -------------------------------- ### Remove management canister from @dfinity/agent Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md The management canister actor has been removed from @dfinity/agent. Use the @dfinity/ic-management package instead. ```typescript import { getManagementCanister } from '@dfinity/agent'; const management = getManagementCanister({ agent }); ``` -------------------------------- ### Renaming Certificate lookup methods Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md Updates to certificate lookup functions and methods to align with the IC Interface Specification. ```typescript // Using standalone functions const lookupResult = lookup_path(['a', 'b'], certificate.tree); const subtreeLookupResult = lookup_path(['subnet', delegation.subnet_id, 'node'], certificate.tree); // Using the Certificate class const lookupResult = certificate.lookup(['a', 'b']); const subtreeLookupResult = certificate.lookup(['subnet', delegation.subnet_id, 'node']); const label = certificate.lookup_label(['path', 'to', 'label']); ``` ```typescript // Using standalone functions const lookupResult = lookup_path(['a', 'b'], certificate.tree); const subtreeLookupResult = lookup_subtree( ['subnet', delegation.subnet_id, 'node'], certificate.tree, ); // Using the Certificate class const lookupResult = certificate.lookup_path(['a', 'b']); const subtreeLookupResult = certificate.lookup_subtree(['subnet', delegation.subnet_id, 'node']); const labelLookupResult = certificate.lookup_path(['path', 'to', 'label']); // or certificate.lookup_subtree(['path', 'to', 'label']) ``` -------------------------------- ### Replace hash function with native or @noble/hashes Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/upgrading/v3.md The hash function has been removed. Use either the asynchronous native crypto.subtle.digest or the synchronous sha256 function from @noble/hashes/sha2. ```typescript import { hash } from '@dfinity/agent'; const hashed = hash(myBuffer); ``` ```typescript // Using the native implementation (asynchronous) const hashes = await globalThis.crypto.subtle.digest('SHA-256', myBuffer); // Using the @noble/hashes/sha2 implementation (synchronous) import { sha256 } from '@noble/hashes/sha2'; const hashed = sha256(myBuffer); ``` -------------------------------- ### Type-Safe Canister Environment Access Source: https://github.com/dfinity/icp-js-core/blob/main/docs/src/content/docs/canister-environment.mdx Extend the CanisterEnv interface by passing a generic type parameter to getCanisterEnv for build-time type safety. ```typescript type MyCanisterEnv = { ['PUBLIC_CANISTER_ID:backend']: string; } const canisterEnv = getCanisterEnv(); console.log(canisterEnv.IC_ROOT_KEY); // served by default by the asset canister console.log(canisterEnv['PUBLIC_CANISTER_ID:backend']); // type-safe access to the environment variable console.log(canisterEnv['PUBLIC_MY_PROPERTY']); // will fail to compile ```