From 27af51ac96a666c77f7b86a77a9290b507fc8de1 Mon Sep 17 00:00:00 2001 From: Alex Ruzenhack Date: Tue, 19 May 2026 13:48:07 +0100 Subject: [PATCH 1/3] feat(audit-trail): initialize wasm client and integrate into context --- .../trustFrameworkProvider.tsx | 13 +++++- .../src/contexts/trustFrameworkContext.ts | 12 +++++ apps/explorer/src/index.tsx | 9 +++- .../lib/constants/trustFramework.constants.ts | 2 + .../src/lib/utils/trust-framework/client.ts | 45 +++++++++++++++++++ 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/apps/explorer/src/components/trust-framework/trustFrameworkProvider.tsx b/apps/explorer/src/components/trust-framework/trustFrameworkProvider.tsx index 39283c0e60..4d595296b2 100644 --- a/apps/explorer/src/components/trust-framework/trustFrameworkProvider.tsx +++ b/apps/explorer/src/components/trust-framework/trustFrameworkProvider.tsx @@ -6,9 +6,12 @@ import { useIotaClient, useIotaClientContext } from '@iota/dapp-kit'; import { type IdentityClientReadOnly } from '@iota/identity-wasm/web'; import { type NotarizationClientReadOnly } from '@iota/notarization/web'; +// TODO: use '@iota/audit-trail/web' after publish +import { type AuditTrailClientReadOnly } from '@iota/audit-trail'; import { type PropsWithChildren, useEffect, useMemo, useState } from 'react'; import { TrustFrameworkContext, type TrustFrameworkProviderContext } from '~/contexts'; import { + createAuditTrailClientReadOnly, createIdentityClientReadOnly, createNotarizationClientReadOnly, } from '~/lib/utils/trust-framework/client'; @@ -20,6 +23,7 @@ export function TrustFrameworkProvider({ children }: PropsWithChildren) { const [notarizationClient, setNotarizationClient] = useState( null, ); + const [auditTrailClient, setAuditTrailClient] = useState(null); useEffect(() => { if (!iotaClient) return; @@ -35,14 +39,21 @@ export function TrustFrameworkProvider({ children }: PropsWithChildren) { setNotarizationClient(_notarizationClient); }; instantiateNotarizationClient(); + + const instantiateAuditTrailClient = async () => { + const _auditTrailClient = await createAuditTrailClientReadOnly(iotaClient, network); + setAuditTrailClient(_auditTrailClient); + }; + instantiateAuditTrailClient(); }, [iotaClient, network]); const ctx = useMemo( (): TrustFrameworkProviderContext => ({ identityClient, notarizationClient, + auditTrailClient, }), - [identityClient, notarizationClient], + [identityClient, notarizationClient, auditTrailClient], ); return {children}; diff --git a/apps/explorer/src/contexts/trustFrameworkContext.ts b/apps/explorer/src/contexts/trustFrameworkContext.ts index bd9da8b024..899c40ff47 100644 --- a/apps/explorer/src/contexts/trustFrameworkContext.ts +++ b/apps/explorer/src/contexts/trustFrameworkContext.ts @@ -5,16 +5,20 @@ import type { IdentityClientReadOnly } from '@iota/identity-wasm/web'; import type { NotarizationClientReadOnly } from '@iota/notarization/web'; +// TODO: use '@iota/audit-trail/web' after publish +import type { AuditTrailClientReadOnly } from '@iota/audit-trail'; import { createContext, useContext } from 'react'; export interface TrustFrameworkProviderContext { identityClient: IdentityClientReadOnly | null; notarizationClient: NotarizationClientReadOnly | null; + auditTrailClient: AuditTrailClientReadOnly | null; } export const TrustFrameworkContext = createContext({ identityClient: null, notarizationClient: null, + auditTrailClient: null, }); export function useTrustFramework(): TrustFrameworkProviderContext { @@ -35,6 +39,10 @@ export function useNotarizationClient(): NotarizationClientReadOnly | null { return useTrustFramework().notarizationClient; } +export function useAuditTrailClient(): AuditTrailClientReadOnly | null { + return useTrustFramework().auditTrailClient; +} + export function useIdentityPkgId(): string | null { return useIdentityClient()?.packageId() || null; } @@ -42,3 +50,7 @@ export function useIdentityPkgId(): string | null { export function useNotarizationPkgId(): string | null { return useNotarizationClient()?.packageId() || null; } + +export function useAuditTrailPkgId(): string | null { + return useAuditTrailClient()?.packageId() || null; +} diff --git a/apps/explorer/src/index.tsx b/apps/explorer/src/index.tsx index 61d7d3f4da..f2117265d1 100644 --- a/apps/explorer/src/index.tsx +++ b/apps/explorer/src/index.tsx @@ -18,7 +18,11 @@ import './index.css'; import { Disclaimer, handleConsentAccepted } from '@iota/core'; import { LEGAL_LINKS } from './lib'; import { Link } from './components'; -import { initIdentityWasmWeb, initNotarizationWasmWeb } from './lib/utils/trust-framework/client'; +import { + initAuditTrailWasmWeb, + initIdentityWasmWeb, + initNotarizationWasmWeb, +} from './lib/utils/trust-framework/client'; // Load Amplitude as early as we can: initAmplitude(); @@ -29,6 +33,9 @@ initIdentityWasmWeb(); // Load Notarization WASM module as early as we can: initNotarizationWasmWeb(); +// Load Audit Trail WASM module as early as we can: +initAuditTrailWasmWeb(); + // Start loading features as early as we can: appsBackendClient.refreshFeatures(); diff --git a/apps/explorer/src/lib/constants/trustFramework.constants.ts b/apps/explorer/src/lib/constants/trustFramework.constants.ts index bc6537847d..8428608a47 100644 --- a/apps/explorer/src/lib/constants/trustFramework.constants.ts +++ b/apps/explorer/src/lib/constants/trustFramework.constants.ts @@ -3,5 +3,7 @@ export const IOTA_IDENTITY_PKG_ID = import.meta.env.VITE_IOTA_IDENTITY_PKG_ID; export const IOTA_NOTARIZATION_PKG_ID = import.meta.env.VITE_IOTA_NOTARIZATION_PKG_ID; +export const IOTA_AUDIT_TRAIL_PKG_ID = import.meta.env.VITE_IOTA_AUDIT_TRAIL_PKG_ID; +export const IOTA_TF_COMPONENTS_PKG_ID = import.meta.env.VITE_IOTA_TF_COMPONENTS_PKG_ID; export const DID_PROTOCOL_SEGMENT_SYMBOL = ':'; export const DID_URL_SEGMENT_SYMBOL = '-'; diff --git a/apps/explorer/src/lib/utils/trust-framework/client.ts b/apps/explorer/src/lib/utils/trust-framework/client.ts index da2995902b..9208b400d2 100644 --- a/apps/explorer/src/lib/utils/trust-framework/client.ts +++ b/apps/explorer/src/lib/utils/trust-framework/client.ts @@ -5,17 +5,23 @@ import * as identity from '@iota/identity-wasm/web'; import identityWasmUrl from '@iota/identity-wasm/web/identity_wasm_bg.wasm?url'; import * as notarization from '@iota/notarization/web'; import notarizationWasmUrl from '@iota/notarization/web/notarization_wasm_bg.wasm?url'; +// TODO: update module to `@iota/audit-trail/web when it is published +import * as auditTrail from '@iota/audit-trail'; +import auditTrailWasmUrl from '@iota/audit-trail/audit_trail_wasm_bg.wasm?url'; import { type IotaClient, Network } from '@iota/iota-sdk/client'; import { DID_PROTOCOL_SEGMENT_SYMBOL, DID_URL_SEGMENT_SYMBOL, IOTA_IDENTITY_PKG_ID, IOTA_NOTARIZATION_PKG_ID, + IOTA_AUDIT_TRAIL_PKG_ID, + IOTA_TF_COMPONENTS_PKG_ID, } from '~/lib/constants/trustFramework.constants'; const regularNetworks = new Set([Network.Mainnet, Network.Testnet, Network.Devnet]); let initIdentityPromise: Promise | null = null; let initNotarizationPromise: Promise | null = null; +let initAuditTrailPromise: Promise | null = null; /** * Idempotent initialization of WASM module of Identity. @@ -49,6 +55,22 @@ export const initNotarizationWasmWeb = async (): Promise => { return initNotarizationPromise; }; +/** + * Idempotent initialization of WASM module of Audit Trail. + * + * Use it everytime you need to call any audit trail API. + */ +export const initAuditTrailWasmWeb = async (): Promise => { + if (!initAuditTrailPromise) { + initAuditTrailPromise = auditTrail.init(auditTrailWasmUrl).catch((e) => { + console.error('failed to load audit trail wasm (web version)', e); + initAuditTrailPromise = null; // allow retry + throw e; + }); + } + return initAuditTrailPromise; +}; + export const createIdentityClientReadOnly = async ( iotaClient: IotaClient, network: string, @@ -95,6 +117,29 @@ export const createNotarizationClientReadOnly = async ( ); }; +export const createAuditTrailClientReadOnly = async ( + iotaClient: IotaClient, + network: string, +): Promise => { + // If IOTA_AUDIT_TRAIL_PKG_ID is declared it has precedence + await initAuditTrailWasmWeb(); + if (IOTA_AUDIT_TRAIL_PKG_ID != null && IOTA_TF_COMPONENTS_PKG_ID != null) { + return await auditTrail.AuditTrailClientReadOnly.createWithPackageOverrides( + iotaClient, + new auditTrail.PackageOverrides(IOTA_AUDIT_TRAIL_PKG_ID, IOTA_TF_COMPONENTS_PKG_ID), + ); + } + + // Well-known networks have well-known notarization package id + if (regularNetworks.has(network as Network)) { + return await auditTrail.AuditTrailClientReadOnly.create(iotaClient); + } + + throw new Error( + 'Failed to create a AuditTrailClientReadOnly; declare IOTA_AUDIT_TRAIL_PKG_ID and IOTA_TF_COMPONENTS_PKG_ID environment if running on a custom network.', + ); +}; + export async function tryDIDParse(didCandidate: string): Promise { try { await initIdentityWasmWeb(); From d9c8c8ead39f78ab6df99d493bb8f014cb8574e0 Mon Sep 17 00:00:00 2001 From: Alex Ruzenhack Date: Mon, 15 Jun 2026 16:41:55 +0100 Subject: [PATCH 2/3] chore: replace audit-trails module import --- .../src/components/trust-framework/trustFrameworkProvider.tsx | 3 +-- apps/explorer/src/contexts/trustFrameworkContext.ts | 3 +-- apps/explorer/src/lib/utils/trust-framework/client.ts | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/explorer/src/components/trust-framework/trustFrameworkProvider.tsx b/apps/explorer/src/components/trust-framework/trustFrameworkProvider.tsx index 4d595296b2..a409fe1671 100644 --- a/apps/explorer/src/components/trust-framework/trustFrameworkProvider.tsx +++ b/apps/explorer/src/components/trust-framework/trustFrameworkProvider.tsx @@ -6,8 +6,7 @@ import { useIotaClient, useIotaClientContext } from '@iota/dapp-kit'; import { type IdentityClientReadOnly } from '@iota/identity-wasm/web'; import { type NotarizationClientReadOnly } from '@iota/notarization/web'; -// TODO: use '@iota/audit-trail/web' after publish -import { type AuditTrailClientReadOnly } from '@iota/audit-trail'; +import { type AuditTrailClientReadOnly } from '@iota/audit-trails/web'; import { type PropsWithChildren, useEffect, useMemo, useState } from 'react'; import { TrustFrameworkContext, type TrustFrameworkProviderContext } from '~/contexts'; import { diff --git a/apps/explorer/src/contexts/trustFrameworkContext.ts b/apps/explorer/src/contexts/trustFrameworkContext.ts index 899c40ff47..6e9390e31e 100644 --- a/apps/explorer/src/contexts/trustFrameworkContext.ts +++ b/apps/explorer/src/contexts/trustFrameworkContext.ts @@ -5,8 +5,7 @@ import type { IdentityClientReadOnly } from '@iota/identity-wasm/web'; import type { NotarizationClientReadOnly } from '@iota/notarization/web'; -// TODO: use '@iota/audit-trail/web' after publish -import type { AuditTrailClientReadOnly } from '@iota/audit-trail'; +import type { AuditTrailClientReadOnly } from '@iota/audit-trails/web'; import { createContext, useContext } from 'react'; export interface TrustFrameworkProviderContext { diff --git a/apps/explorer/src/lib/utils/trust-framework/client.ts b/apps/explorer/src/lib/utils/trust-framework/client.ts index 9208b400d2..cee0278102 100644 --- a/apps/explorer/src/lib/utils/trust-framework/client.ts +++ b/apps/explorer/src/lib/utils/trust-framework/client.ts @@ -5,8 +5,7 @@ import * as identity from '@iota/identity-wasm/web'; import identityWasmUrl from '@iota/identity-wasm/web/identity_wasm_bg.wasm?url'; import * as notarization from '@iota/notarization/web'; import notarizationWasmUrl from '@iota/notarization/web/notarization_wasm_bg.wasm?url'; -// TODO: update module to `@iota/audit-trail/web when it is published -import * as auditTrail from '@iota/audit-trail'; +import * as auditTrail from '@iota/audit-trails/web'; import auditTrailWasmUrl from '@iota/audit-trail/audit_trail_wasm_bg.wasm?url'; import { type IotaClient, Network } from '@iota/iota-sdk/client'; import { From b8e2a8fc0c7d94ccb419f43e2ce258698b80a0f9 Mon Sep 17 00:00:00 2001 From: Alex Ruzenhack Date: Mon, 15 Jun 2026 18:49:34 +0100 Subject: [PATCH 3/3] fix: wasm import for audit-trails --- apps/explorer/src/lib/utils/trust-framework/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/explorer/src/lib/utils/trust-framework/client.ts b/apps/explorer/src/lib/utils/trust-framework/client.ts index cee0278102..ff01f5a611 100644 --- a/apps/explorer/src/lib/utils/trust-framework/client.ts +++ b/apps/explorer/src/lib/utils/trust-framework/client.ts @@ -6,7 +6,7 @@ import identityWasmUrl from '@iota/identity-wasm/web/identity_wasm_bg.wasm?url'; import * as notarization from '@iota/notarization/web'; import notarizationWasmUrl from '@iota/notarization/web/notarization_wasm_bg.wasm?url'; import * as auditTrail from '@iota/audit-trails/web'; -import auditTrailWasmUrl from '@iota/audit-trail/audit_trail_wasm_bg.wasm?url'; +import auditTrailWasmUrl from '@iota/audit-trails/web/audit_trail_wasm_bg.wasm?url'; import { type IotaClient, Network } from '@iota/iota-sdk/client'; import { DID_PROTOCOL_SEGMENT_SYMBOL,