@temple-digital-group/temple-canton-js 2.0.5 → 2.0.6-beta-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import config from "../../src/config/index.js";
2
2
  import axios from "axios";
3
3
  import { getDisclosures } from "../api/index.js";
4
4
  import { getUserId } from "../api/tokenStore.js";
5
- import { getAdapterPartyId, getWalletAdapter, submitCommand, payDueGasIfAny } from "../../src/canton/walletAdapter.js";
5
+ import { getAdapterPartyId, getWalletAdapter, submitCommand, payDueGasIfAny } from "./walletAdapter.js";
6
6
  import { normalizeAssetId, instrumentCatalog, instrumentIdToSymbol, resolveOnChainInstrumentId } from "../../src/canton/instrumentCatalog.js";
7
7
  import { randomUUID, shouldUseLedgerForMetadata, normalizeContractId, resolveInstrumentDefinition, getInstrumentRegistrar, resolveProvider, dedupeDisclosedContracts, buildHeaders, DEFAULT_UTILITY_CONTEXT_KEYS, } from "./helpers.js";
8
8
  import { resolveAmuletContext, resolveUtilityInstrumentConfiguration, resolveUtilityAllocationFactory, getAmuletHoldingsForParty, getUtilityHoldingsForParty, getUtxoCount, getAmuletRules, getOpenMiningRounds, } from "../../src/canton/index.js";
@@ -298,6 +298,7 @@ export async function depositFunds(opts, returnCommand = false) {
298
298
  return { error: msg };
299
299
  }
300
300
  const isAmulet = assetId === "Amulet";
301
+ const usingWalletAdapter = Boolean(getWalletAdapter());
301
302
  // --- 1. Resolve admin and factory ---
302
303
  let admin;
303
304
  let factoryContractId;
@@ -319,7 +320,7 @@ export async function depositFunds(opts, returnCommand = false) {
319
320
  if (isAmulet && (!allocateBefore || !settleBefore)) {
320
321
  // Compute the safe deadline from on-chain fee params to avoid
321
322
  // "amulet expires before lock" errors on small amounts.
322
- const expiryParams = await fetchAmuletExpiryParams(config.VALIDATOR_DSO_PARTY_ID);
323
+ const expiryParams = usingWalletAdapter ? null : await fetchAmuletExpiryParams(config.VALIDATOR_DSO_PARTY_ID);
323
324
  const maxExpiry = expiryParams ? maxLockExpirationForFreshAmulet(amount, expiryParams) : null;
324
325
  if (maxExpiry) {
325
326
  // settleBefore = safe max expiry; allocateBefore = halfway between now and settleBefore
@@ -16,7 +16,6 @@ export declare const DEFAULT_UTILITY_CONTEXT_KEYS: {
16
16
  readonly featuredAppRight: "featured-app-right";
17
17
  readonly featuredAppRightPrefixed: "utility.digitalasset.com/featured-app-right";
18
18
  };
19
- export declare const LOCAL_VALIDATOR_HOSTNAMES: Set<string>;
20
19
  export declare const FORCE_LEDGER_METADATA: boolean;
21
20
  export interface DisclosedContract {
22
21
  templateId: string | null;
@@ -58,15 +57,17 @@ export interface ActiveContractEntry {
58
57
  }
59
58
  /** Cross-platform UUID generation. */
60
59
  export declare const randomUUID: () => string;
61
- /** Check if a validator URL points to localhost. */
62
- export declare function isLocalValidatorUrl(urlValue: string | undefined | null): boolean;
63
60
  /** Determine if ledger should be used for metadata resolution. */
64
61
  export declare function shouldUseLedgerForMetadata(): boolean;
65
62
  /** Trim a contract ID string. */
66
63
  export declare function normalizeContractId(value: unknown): unknown;
67
64
  /** Recursively normalize contract references in an object. */
68
65
  export declare function normalizeContractReferences(value: unknown): unknown;
69
- /** Resolve provider: use the passed value, or fall back to the wallet adapter's provider. */
66
+ /**
67
+ * Resolve the active-contracts reader: the explicit provider override when given,
68
+ * otherwise the active wallet adapter (the universal wrapper). Returns null when
69
+ * no wallet source is available, so callers fall back to the ledger API.
70
+ */
70
71
  export declare function resolveProvider(provider: unknown): unknown;
71
72
  /** Resolve an instrument definition from the catalog. */
72
73
  export declare function resolveInstrumentDefinition(assetId: string): Record<string, unknown> | null;
@@ -1,7 +1,7 @@
1
1
  import config from "../../src/config/index.js";
2
2
  import axios from "axios";
3
3
  import { getJWTToken } from "../../src/auth0/index.js";
4
- import { getAdapterProvider } from "../../src/canton/walletAdapter.js";
4
+ import { getActiveContractReader } from "./wallet/service.js";
5
5
  import { instrumentCatalog, normalizeAssetId } from "../../src/canton/instrumentCatalog.js";
6
6
  // ─── Constants ───────────────────────────────────────────────────────────────
7
7
  export const DEFAULT_AMULET_CONTEXT_KEYS = {
@@ -22,7 +22,6 @@ export const DEFAULT_UTILITY_CONTEXT_KEYS = {
22
22
  featuredAppRight: "featured-app-right",
23
23
  featuredAppRightPrefixed: "utility.digitalasset.com/featured-app-right",
24
24
  };
25
- export const LOCAL_VALIDATOR_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1", "0.0.0.0"]);
26
25
  export const FORCE_LEDGER_METADATA = typeof process !== "undefined" && process.env
27
26
  ? String(process.env.FORCE_LEDGER_METADATA || "").toLowerCase() === "true"
28
27
  : false;
@@ -42,25 +41,11 @@ export const randomUUID = () => {
42
41
  return v.toString(16);
43
42
  });
44
43
  };
45
- /** Check if a validator URL points to localhost. */
46
- export function isLocalValidatorUrl(urlValue) {
47
- if (!urlValue)
48
- return false;
49
- try {
50
- const parsed = new URL(urlValue);
51
- return LOCAL_VALIDATOR_HOSTNAMES.has(parsed.hostname.toLowerCase());
52
- }
53
- catch {
54
- return false;
55
- }
56
- }
57
44
  /** Determine if ledger should be used for metadata resolution. */
58
45
  export function shouldUseLedgerForMetadata() {
59
- if (FORCE_LEDGER_METADATA)
60
- return true;
61
46
  if (!config.VALIDATOR_API_URL)
62
47
  return false;
63
- return isLocalValidatorUrl(config.VALIDATOR_API_URL);
48
+ return FORCE_LEDGER_METADATA;
64
49
  }
65
50
  /** Trim a contract ID string. */
66
51
  export function normalizeContractId(value) {
@@ -89,9 +74,13 @@ export function normalizeContractReferences(value) {
89
74
  }
90
75
  return value;
91
76
  }
92
- /** Resolve provider: use the passed value, or fall back to the wallet adapter's provider. */
77
+ /**
78
+ * Resolve the active-contracts reader: the explicit provider override when given,
79
+ * otherwise the active wallet adapter (the universal wrapper). Returns null when
80
+ * no wallet source is available, so callers fall back to the ledger API.
81
+ */
93
82
  export function resolveProvider(provider) {
94
- return provider || getAdapterProvider() || null;
83
+ return getActiveContractReader(provider);
95
84
  }
96
85
  // ─── Instrument Catalog ──────────────────────────────────────────────────────
97
86
  /** Resolve an instrument definition from the catalog. */
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Universal Wallet Adapter contract.
3
+ *
4
+ * Every wallet (Loop, and future providers such as Console or BitGo) is
5
+ * represented as a *normalized adapter* implementing the capability interface
6
+ * defined here. The rest of the SDK never talks to a wallet/provider SDK
7
+ * directly — it goes through the wallet service (./service.js), which dispatches
8
+ * to the active adapter.
9
+ *
10
+ * Capabilities are split into two tiers:
11
+ *
12
+ * - REQUIRED: getPartyId, getActiveContracts, submitCommand.
13
+ * A wallet that cannot provide these is not usable. `defineWalletAdapter`
14
+ * throws if a factory omits one, and the service throws if a required
15
+ * capability is invoked while no adapter is configured.
16
+ *
17
+ * - OPTIONAL: payDueGasIfAny, getHolding, getAmuletRules, getOpenMiningRounds,
18
+ * disconnect. Not every wallet supports these (e.g. a custodial wallet may
19
+ * handle fees itself, a non-amulet wallet has no mining rounds). When a
20
+ * factory omits an optional capability, it is filled with a safe no-op so
21
+ * callers can invoke it unconditionally — it simply "passes".
22
+ *
23
+ * Add a new wallet by writing a `create<Name>WalletAdapter()` factory that
24
+ * builds a definition object and returns `defineWalletAdapter(definition)`.
25
+ */
26
+ /** A normalized wallet adapter produced by {@link defineWalletAdapter}. */
27
+ export interface WalletAdapter {
28
+ /** Provider id, e.g. "loop". */
29
+ readonly id: string;
30
+ /** True for server-side adapters that sign/submit locally. */
31
+ readonly isServer: boolean;
32
+ /** Resolve the wallet's primary party id. */
33
+ getPartyId(): string | null;
34
+ /** Read active contracts matching `args` via the wallet. */
35
+ getActiveContracts(args: unknown): Promise<unknown>;
36
+ /** Sign and submit a ledger command via the wallet. */
37
+ submitCommand(command: unknown): Promise<unknown>;
38
+ /** Pay any outstanding network gas. No-op when unsupported. */
39
+ payDueGasIfAny(): Promise<void>;
40
+ /** Read a holding via the wallet. Resolves null when unsupported. */
41
+ getHolding(...args: unknown[]): Promise<unknown>;
42
+ /** Resolve amulet rules via the wallet. Resolves null when unsupported. */
43
+ getAmuletRules(...args: unknown[]): Promise<unknown>;
44
+ /** Resolve open mining rounds via the wallet. Resolves null when unsupported. */
45
+ getOpenMiningRounds(...args: unknown[]): Promise<unknown>;
46
+ /** Disconnect the wallet. No-op when unsupported. */
47
+ disconnect(): Promise<void>;
48
+ /** Raw provider object for legacy getAdapterProvider() consumers, or null. */
49
+ getRawProvider(): unknown;
50
+ }
51
+ /** Capability definition supplied by a `create<Name>WalletAdapter()` factory. */
52
+ export interface WalletAdapterDefinition {
53
+ id?: string;
54
+ isServer?: boolean;
55
+ getPartyId(): string | null;
56
+ getActiveContracts(args: unknown): Promise<unknown> | unknown;
57
+ submitCommand(command: unknown): Promise<unknown> | unknown;
58
+ payDueGasIfAny?(): Promise<void> | void;
59
+ getHolding?(...args: unknown[]): Promise<unknown> | unknown;
60
+ getAmuletRules?(...args: unknown[]): Promise<unknown> | unknown;
61
+ getOpenMiningRounds?(...args: unknown[]): Promise<unknown> | unknown;
62
+ disconnect?(): Promise<void> | void;
63
+ getRawProvider?(): unknown;
64
+ }
65
+ /** Required capabilities — a usable wallet adapter must implement all of these. */
66
+ export declare const REQUIRED_CAPABILITIES: readonly ["getPartyId", "getActiveContracts", "submitCommand"];
67
+ /** Optional capabilities — filled with safe no-ops when a wallet does not support them. */
68
+ export declare const OPTIONAL_CAPABILITIES: readonly ["payDueGasIfAny", "getHolding", "getAmuletRules", "getOpenMiningRounds", "disconnect"];
69
+ /** Returns true if `value` was produced by {@link defineWalletAdapter}. */
70
+ export declare function isWalletAdapter(value: unknown): value is WalletAdapter;
71
+ /**
72
+ * Build a normalized wallet adapter from a factory definition.
73
+ *
74
+ * Validates that every required capability is implemented and fills any missing
75
+ * optional capability with a safe no-op. The returned object is branded so the
76
+ * service and facade can distinguish it from a raw provider SDK instance.
77
+ */
78
+ export declare function defineWalletAdapter(definition: WalletAdapterDefinition): WalletAdapter;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Universal Wallet Adapter contract.
3
+ *
4
+ * Every wallet (Loop, and future providers such as Console or BitGo) is
5
+ * represented as a *normalized adapter* implementing the capability interface
6
+ * defined here. The rest of the SDK never talks to a wallet/provider SDK
7
+ * directly — it goes through the wallet service (./service.js), which dispatches
8
+ * to the active adapter.
9
+ *
10
+ * Capabilities are split into two tiers:
11
+ *
12
+ * - REQUIRED: getPartyId, getActiveContracts, submitCommand.
13
+ * A wallet that cannot provide these is not usable. `defineWalletAdapter`
14
+ * throws if a factory omits one, and the service throws if a required
15
+ * capability is invoked while no adapter is configured.
16
+ *
17
+ * - OPTIONAL: payDueGasIfAny, getHolding, getAmuletRules, getOpenMiningRounds,
18
+ * disconnect. Not every wallet supports these (e.g. a custodial wallet may
19
+ * handle fees itself, a non-amulet wallet has no mining rounds). When a
20
+ * factory omits an optional capability, it is filled with a safe no-op so
21
+ * callers can invoke it unconditionally — it simply "passes".
22
+ *
23
+ * Add a new wallet by writing a `create<Name>WalletAdapter()` factory that
24
+ * builds a definition object and returns `defineWalletAdapter(definition)`.
25
+ */
26
+ /** Required capabilities — a usable wallet adapter must implement all of these. */
27
+ export const REQUIRED_CAPABILITIES = ["getPartyId", "getActiveContracts", "submitCommand"];
28
+ /** Optional capabilities — filled with safe no-ops when a wallet does not support them. */
29
+ export const OPTIONAL_CAPABILITIES = ["payDueGasIfAny", "getHolding", "getAmuletRules", "getOpenMiningRounds", "disconnect"];
30
+ /** Brand used to recognize objects produced by {@link defineWalletAdapter}. */
31
+ const ADAPTER_BRAND = Symbol.for("temple.canton.walletAdapter");
32
+ /**
33
+ * Safe no-op implementations for optional capabilities. Each returns a benign
34
+ * "nothing to do" value so a wallet that lacks the capability still passes when
35
+ * a caller invokes it. The comments explain why a no-op is the correct default.
36
+ */
37
+ const OPTIONAL_NO_OPS = {
38
+ // Networks/wallets with no programmatic gas concept (or where fees are paid
39
+ // wallet-side, e.g. a custodial provider) have nothing to settle here.
40
+ payDueGasIfAny: async () => undefined,
41
+ // Wallet does not expose its own holdings read — callers fall back to the
42
+ // ledger API, so "no wallet-side holdings" is represented as null.
43
+ getHolding: async () => null,
44
+ // Amulet-specific context. A non-Canton-amulet wallet simply has no rules to
45
+ // provide; null lets callers fall back to the ledger/scan lookups.
46
+ getAmuletRules: async () => null,
47
+ getOpenMiningRounds: async () => null,
48
+ // Stateless/headless wallets hold no connection to tear down.
49
+ disconnect: async () => undefined,
50
+ };
51
+ /** Returns true if `value` was produced by {@link defineWalletAdapter}. */
52
+ export function isWalletAdapter(value) {
53
+ return Boolean(value && value[ADAPTER_BRAND] === true);
54
+ }
55
+ /**
56
+ * Build a normalized wallet adapter from a factory definition.
57
+ *
58
+ * Validates that every required capability is implemented and fills any missing
59
+ * optional capability with a safe no-op. The returned object is branded so the
60
+ * service and facade can distinguish it from a raw provider SDK instance.
61
+ */
62
+ export function defineWalletAdapter(definition) {
63
+ if (!definition || typeof definition !== "object") {
64
+ throw new Error("[Temple SDK] Wallet adapter definition must be an object.");
65
+ }
66
+ const id = typeof definition.id === "string" && definition.id ? definition.id : "unknown";
67
+ for (const capability of REQUIRED_CAPABILITIES) {
68
+ if (typeof definition[capability] !== "function") {
69
+ throw new Error(`[Temple SDK] Wallet adapter "${id}" is missing required capability: ${capability}().`);
70
+ }
71
+ }
72
+ const adapter = {
73
+ [ADAPTER_BRAND]: true,
74
+ id,
75
+ isServer: Boolean(definition.isServer),
76
+ // Required capabilities (validated above).
77
+ getPartyId: definition.getPartyId,
78
+ getActiveContracts: definition.getActiveContracts,
79
+ submitCommand: definition.submitCommand,
80
+ // Optional capabilities — fall back to a safe no-op when a wallet omits them.
81
+ payDueGasIfAny: typeof definition.payDueGasIfAny === "function" ? definition.payDueGasIfAny : OPTIONAL_NO_OPS.payDueGasIfAny,
82
+ getHolding: typeof definition.getHolding === "function" ? definition.getHolding : OPTIONAL_NO_OPS.getHolding,
83
+ getAmuletRules: typeof definition.getAmuletRules === "function" ? definition.getAmuletRules : OPTIONAL_NO_OPS.getAmuletRules,
84
+ getOpenMiningRounds: typeof definition.getOpenMiningRounds === "function" ? definition.getOpenMiningRounds : OPTIONAL_NO_OPS.getOpenMiningRounds,
85
+ disconnect: typeof definition.disconnect === "function" ? definition.disconnect : OPTIONAL_NO_OPS.disconnect,
86
+ // Escape hatch: the raw provider object for legacy consumers of
87
+ // getAdapterProvider(). Defaults to null when a wallet exposes no such object.
88
+ getRawProvider: typeof definition.getRawProvider === "function" ? definition.getRawProvider : (() => null),
89
+ };
90
+ return adapter;
91
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Loop wallet adapter factory.
3
+ *
4
+ * Wraps a raw Loop SDK instance in the universal wallet adapter interface so the
5
+ * rest of the SDK interacts with Loop through the same contract as every other
6
+ * wallet. This preserves the exact behavior that previously lived inline in
7
+ * walletAdapter.js:
8
+ *
9
+ * - Server-side (Loop): signs locally via executeTransaction().
10
+ * - Client-side (Loop): delegates signing to the Loop Wallet via the provider's
11
+ * submitTransaction().
12
+ * - Reads go through the provider sub-object (loop.provider) when present.
13
+ *
14
+ * Server vs client is detected from the Loop connection: a server-side instance
15
+ * has a null connection.ticketId and connection.ws.
16
+ */
17
+ import { type WalletAdapter } from "./adapter.js";
18
+ /**
19
+ * Create a universal wallet adapter backed by a Loop SDK instance.
20
+ */
21
+ export declare function createLoopWalletAdapter(loop: unknown): WalletAdapter;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Loop wallet adapter factory.
3
+ *
4
+ * Wraps a raw Loop SDK instance in the universal wallet adapter interface so the
5
+ * rest of the SDK interacts with Loop through the same contract as every other
6
+ * wallet. This preserves the exact behavior that previously lived inline in
7
+ * walletAdapter.js:
8
+ *
9
+ * - Server-side (Loop): signs locally via executeTransaction().
10
+ * - Client-side (Loop): delegates signing to the Loop Wallet via the provider's
11
+ * submitTransaction().
12
+ * - Reads go through the provider sub-object (loop.provider) when present.
13
+ *
14
+ * Server vs client is detected from the Loop connection: a server-side instance
15
+ * has a null connection.ticketId and connection.ws.
16
+ */
17
+ import { defineWalletAdapter } from "./adapter.js";
18
+ /**
19
+ * Detect whether a Loop instance is server-side.
20
+ * Loop-specific: server-side has null connection.ticketId and connection.ws.
21
+ * With no connection object, assume server-side (headless/API usage).
22
+ */
23
+ function detectServerSide(loop) {
24
+ if (loop.connection) {
25
+ return loop.connection.ticketId == null && loop.connection.ws == null;
26
+ }
27
+ return true;
28
+ }
29
+ /**
30
+ * Create a universal wallet adapter backed by a Loop SDK instance.
31
+ */
32
+ export function createLoopWalletAdapter(loop) {
33
+ if (!loop || typeof loop !== "object") {
34
+ throw new Error("[Temple SDK] createLoopWalletAdapter requires a Loop wallet instance.");
35
+ }
36
+ const sdk = loop;
37
+ const isServer = detectServerSide(sdk);
38
+ // The provider sub-object handles reads (getActiveContracts) and client-side
39
+ // submission (submitTransaction). Fall back to the instance itself.
40
+ const provider = sdk.provider || sdk;
41
+ return defineWalletAdapter({
42
+ id: "loop",
43
+ isServer,
44
+ getRawProvider: () => provider,
45
+ // ── Required capabilities ──
46
+ getPartyId: () => sdk.provider?.party_id || sdk.session?.partyId || null,
47
+ getActiveContracts: (args) => {
48
+ if (typeof provider.getActiveContracts !== "function") {
49
+ throw new Error("[Temple SDK] Loop provider does not support getActiveContracts().");
50
+ }
51
+ return provider.getActiveContracts(args);
52
+ },
53
+ submitCommand: (command) => {
54
+ // Server-side: sign locally with the private key.
55
+ if (isServer && typeof sdk.executeTransaction === "function") {
56
+ return sdk.executeTransaction(command);
57
+ }
58
+ // Client-side: delegate signing to the Loop Wallet via WebSocket.
59
+ if (typeof provider.submitTransaction === "function") {
60
+ return provider.submitTransaction(command);
61
+ }
62
+ throw new Error("[Temple SDK] Loop wallet adapter does not support transaction submission.");
63
+ },
64
+ // ── Optional capabilities ──
65
+ // Loop pays network gas programmatically only on the server side; the
66
+ // client-side flow is handled by the Loop Wallet UI, so it is a no-op here.
67
+ payDueGasIfAny: async () => {
68
+ if (!isServer)
69
+ return;
70
+ if (typeof sdk.checkDueGas !== "function" || typeof sdk.payGas !== "function")
71
+ return;
72
+ try {
73
+ const dueGas = await sdk.checkDueGas();
74
+ const trackingId = dueGas?.tracking_id;
75
+ if (dueGas?.pending && trackingId) {
76
+ console.log(`[Temple SDK] Paying outstanding network gas (tracking_id=${trackingId})`);
77
+ await sdk.payGas(trackingId);
78
+ }
79
+ }
80
+ catch (error) {
81
+ console.warn(`[Temple SDK] checkDueGas/payGas failed: ${error?.message || String(error)}`);
82
+ }
83
+ },
84
+ // getHolding / getAmuletRules / getOpenMiningRounds / disconnect: not
85
+ // provided by Loop here — the adapter inherits the safe no-op defaults.
86
+ });
87
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Universal wallet service.
3
+ *
4
+ * Holds the single active wallet adapter and dispatches capability calls to it.
5
+ * This is the one chokepoint the rest of the SDK uses to reach a wallet — no
6
+ * module talks to a provider/wallet SDK directly.
7
+ *
8
+ * - Required capabilities (getPartyId, submitCommand) throw a clear error when
9
+ * invoked while no adapter is configured.
10
+ * - Active-contract reads are resolved through `getActiveContractReader`, which
11
+ * supports an explicit per-call provider override and returns null when no
12
+ * wallet source is available so callers can fall back to the ledger API.
13
+ * - Optional capabilities (payDueGasIfAny) become safe no-ops when no adapter
14
+ * is set.
15
+ */
16
+ import { type WalletAdapter } from "./adapter.js";
17
+ /** Register the active wallet adapter. Pass null to clear it. */
18
+ export declare function setActiveAdapter(adapter: WalletAdapter | null): void;
19
+ /** Get the active wallet adapter, or null when none is set. */
20
+ export declare function getActiveAdapter(): WalletAdapter | null;
21
+ /** True when a wallet adapter is configured. */
22
+ export declare function hasActiveAdapter(): boolean;
23
+ /** Resolve the active wallet's party id. Throws when no adapter is configured. */
24
+ export declare function getPartyId(): string | null;
25
+ /** Sign and submit a ledger command. Throws when no adapter is configured. */
26
+ export declare function submitCommand(command: unknown): Promise<unknown>;
27
+ /**
28
+ * Resolve the object used to read active contracts.
29
+ *
30
+ * An explicit `providerOverride` wins (a caller intentionally bypassing the
31
+ * active wallet); otherwise the active adapter — the universal wrapper — is
32
+ * returned, exposing its normalized `getActiveContracts` capability. Returns
33
+ * null when neither is available, signalling callers to fall back to the
34
+ * ledger API.
35
+ */
36
+ export declare function getActiveContractReader(providerOverride?: unknown): unknown;
37
+ /**
38
+ * Pay any outstanding network gas before a read/submit. Safe no-op when no
39
+ * adapter is configured (e.g. pure ledger/server mode without a wallet).
40
+ */
41
+ export declare function payDueGasIfAny(): Promise<void>;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Universal wallet service.
3
+ *
4
+ * Holds the single active wallet adapter and dispatches capability calls to it.
5
+ * This is the one chokepoint the rest of the SDK uses to reach a wallet — no
6
+ * module talks to a provider/wallet SDK directly.
7
+ *
8
+ * - Required capabilities (getPartyId, submitCommand) throw a clear error when
9
+ * invoked while no adapter is configured.
10
+ * - Active-contract reads are resolved through `getActiveContractReader`, which
11
+ * supports an explicit per-call provider override and returns null when no
12
+ * wallet source is available so callers can fall back to the ledger API.
13
+ * - Optional capabilities (payDueGasIfAny) become safe no-ops when no adapter
14
+ * is set.
15
+ */
16
+ import { isWalletAdapter } from "./adapter.js";
17
+ /** The single active, normalized wallet adapter (or null when none is set). */
18
+ let _activeAdapter = null;
19
+ /** Register the active wallet adapter. Pass null to clear it. */
20
+ export function setActiveAdapter(adapter) {
21
+ if (adapter && !isWalletAdapter(adapter)) {
22
+ throw new Error("[Temple SDK] setActiveAdapter expects a normalized wallet adapter created by a create*WalletAdapter() factory.");
23
+ }
24
+ _activeAdapter = adapter || null;
25
+ }
26
+ /** Get the active wallet adapter, or null when none is set. */
27
+ export function getActiveAdapter() {
28
+ return _activeAdapter;
29
+ }
30
+ /** True when a wallet adapter is configured. */
31
+ export function hasActiveAdapter() {
32
+ return _activeAdapter !== null;
33
+ }
34
+ function requireAdapter() {
35
+ if (!_activeAdapter) {
36
+ throw new Error("[Temple SDK] No wallet adapter configured. Call initialize() with WALLET_ADAPTER or setWalletAdapter() first.");
37
+ }
38
+ return _activeAdapter;
39
+ }
40
+ // ── Required capabilities ──────────────────────────────────────────────────
41
+ /** Resolve the active wallet's party id. Throws when no adapter is configured. */
42
+ export function getPartyId() {
43
+ return requireAdapter().getPartyId();
44
+ }
45
+ /** Sign and submit a ledger command. Throws when no adapter is configured. */
46
+ export function submitCommand(command) {
47
+ return requireAdapter().submitCommand(command);
48
+ }
49
+ /**
50
+ * Resolve the object used to read active contracts.
51
+ *
52
+ * An explicit `providerOverride` wins (a caller intentionally bypassing the
53
+ * active wallet); otherwise the active adapter — the universal wrapper — is
54
+ * returned, exposing its normalized `getActiveContracts` capability. Returns
55
+ * null when neither is available, signalling callers to fall back to the
56
+ * ledger API.
57
+ */
58
+ export function getActiveContractReader(providerOverride = null) {
59
+ if (providerOverride)
60
+ return providerOverride;
61
+ return _activeAdapter || null;
62
+ }
63
+ // ── Optional capabilities ──────────────────────────────────────────────────
64
+ /**
65
+ * Pay any outstanding network gas before a read/submit. Safe no-op when no
66
+ * adapter is configured (e.g. pure ledger/server mode without a wallet).
67
+ */
68
+ export async function payDueGasIfAny() {
69
+ if (!_activeAdapter)
70
+ return;
71
+ return _activeAdapter.payDueGasIfAny();
72
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Wallet Adapter Facade
3
+ *
4
+ * Backward-compatible public surface for wallet interactions. The real wallet
5
+ * architecture lives in ./wallet/ — a universal adapter contract (adapter.ts),
6
+ * a service registry that dispatches capability calls (service.ts), and one
7
+ * factory per wallet (loop.ts, and future providers). This module is a thin
8
+ * facade over that service so existing imports keep working unchanged.
9
+ *
10
+ * Adding a new wallet does not touch this file: write a create<Name>WalletAdapter()
11
+ * factory and pass its result to setWalletAdapter().
12
+ */
13
+ import type { WalletAdapter } from "./wallet/adapter.js";
14
+ export { createLoopWalletAdapter } from "./wallet/loop.js";
15
+ export { defineWalletAdapter, isWalletAdapter } from "./wallet/adapter.js";
16
+ export type { WalletAdapter, WalletAdapterDefinition } from "./wallet/adapter.js";
17
+ /**
18
+ * Set the active wallet adapter.
19
+ *
20
+ * Accepts either a normalized adapter (from a create*WalletAdapter() factory) or
21
+ * a raw Loop SDK instance, which is auto-wrapped for backward compatibility.
22
+ * Pass a falsy value to clear the adapter.
23
+ */
24
+ export declare function setWalletAdapter(adapter: unknown): void;
25
+ /**
26
+ * Get the active (normalized) wallet adapter, or null when none is set.
27
+ */
28
+ export declare function getWalletAdapter(): WalletAdapter | null;
29
+ /**
30
+ * Returns the provider sub-object used for read operations (getActiveContracts).
31
+ * Kept for backward compatibility; resolves the active adapter's raw provider.
32
+ */
33
+ export declare function getAdapterProvider(): unknown;
34
+ /**
35
+ * Check if the active adapter runs in server mode.
36
+ */
37
+ export declare function isServerMode(): boolean;
38
+ /**
39
+ * Get the party ID from the active wallet adapter, or null when none is set.
40
+ */
41
+ export declare function getAdapterPartyId(): string | null;
42
+ /**
43
+ * Pay any outstanding network gas before submitting a transaction or reading
44
+ * balances. Safe no-op when no adapter is configured or the wallet handles gas
45
+ * itself.
46
+ */
47
+ export declare function payDueGasIfAny(): Promise<void>;
48
+ /**
49
+ * Submit a command via the active wallet adapter.
50
+ * Throws when no adapter is configured.
51
+ */
52
+ export declare function submitCommand(command: unknown): Promise<unknown>;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Wallet Adapter Facade
3
+ *
4
+ * Backward-compatible public surface for wallet interactions. The real wallet
5
+ * architecture lives in ./wallet/ — a universal adapter contract (adapter.ts),
6
+ * a service registry that dispatches capability calls (service.ts), and one
7
+ * factory per wallet (loop.ts, and future providers). This module is a thin
8
+ * facade over that service so existing imports keep working unchanged.
9
+ *
10
+ * Adding a new wallet does not touch this file: write a create<Name>WalletAdapter()
11
+ * factory and pass its result to setWalletAdapter().
12
+ */
13
+ import { setActiveAdapter, getActiveAdapter, submitCommand as serviceSubmitCommand, payDueGasIfAny as servicePayDueGasIfAny, } from "./wallet/service.js";
14
+ import { isWalletAdapter } from "./wallet/adapter.js";
15
+ import { createLoopWalletAdapter } from "./wallet/loop.js";
16
+ // Re-export the adapter toolkit so consumers can build/register custom wallets.
17
+ export { createLoopWalletAdapter } from "./wallet/loop.js";
18
+ export { defineWalletAdapter, isWalletAdapter } from "./wallet/adapter.js";
19
+ /**
20
+ * Set the active wallet adapter.
21
+ *
22
+ * Accepts either a normalized adapter (from a create*WalletAdapter() factory) or
23
+ * a raw Loop SDK instance, which is auto-wrapped for backward compatibility.
24
+ * Pass a falsy value to clear the adapter.
25
+ */
26
+ export function setWalletAdapter(adapter) {
27
+ if (!adapter) {
28
+ setActiveAdapter(null);
29
+ return;
30
+ }
31
+ const normalized = isWalletAdapter(adapter) ? adapter : createLoopWalletAdapter(adapter);
32
+ setActiveAdapter(normalized);
33
+ }
34
+ /**
35
+ * Get the active (normalized) wallet adapter, or null when none is set.
36
+ */
37
+ export function getWalletAdapter() {
38
+ return getActiveAdapter();
39
+ }
40
+ /**
41
+ * Returns the provider sub-object used for read operations (getActiveContracts).
42
+ * Kept for backward compatibility; resolves the active adapter's raw provider.
43
+ */
44
+ export function getAdapterProvider() {
45
+ const adapter = getActiveAdapter();
46
+ if (!adapter)
47
+ return null;
48
+ return adapter.getRawProvider() || adapter;
49
+ }
50
+ /**
51
+ * Check if the active adapter runs in server mode.
52
+ */
53
+ export function isServerMode() {
54
+ const adapter = getActiveAdapter();
55
+ return adapter ? Boolean(adapter.isServer) : false;
56
+ }
57
+ /**
58
+ * Get the party ID from the active wallet adapter, or null when none is set.
59
+ */
60
+ export function getAdapterPartyId() {
61
+ const adapter = getActiveAdapter();
62
+ return adapter ? adapter.getPartyId() : null;
63
+ }
64
+ /**
65
+ * Pay any outstanding network gas before submitting a transaction or reading
66
+ * balances. Safe no-op when no adapter is configured or the wallet handles gas
67
+ * itself.
68
+ */
69
+ export function payDueGasIfAny() {
70
+ return servicePayDueGasIfAny();
71
+ }
72
+ /**
73
+ * Submit a command via the active wallet adapter.
74
+ * Throws when no adapter is configured.
75
+ */
76
+ export function submitCommand(command) {
77
+ return serviceSubmitCommand(command);
78
+ }
@@ -2,7 +2,7 @@ import config from "../../src/config/index.js";
2
2
  import axios from "axios";
3
3
  import { getDisclosures, createWithdrawalRequest, getWithdrawalRequestStatus, getDelegation, } from "../api/index.js";
4
4
  import { getUserId } from "../api/tokenStore.js";
5
- import { getAdapterPartyId, getWalletAdapter, submitCommand, payDueGasIfAny } from "../../src/canton/walletAdapter.js";
5
+ import { getAdapterPartyId, getWalletAdapter, submitCommand, payDueGasIfAny } from "./walletAdapter.js";
6
6
  import { randomUUID, shouldUseLedgerForMetadata, normalizeContractId, resolveInstrumentDefinition, getInstrumentRegistrar, resolveProvider, dedupeDisclosedContracts, buildHeaders, DEFAULT_AMULET_CONTEXT_KEYS, DEFAULT_UTILITY_CONTEXT_KEYS, } from "./helpers.js";
7
7
  import { resolveAmuletContext, resolveUtilityInstrumentConfiguration, resolveUtilityAllocationFactory, getUtxoCount, } from "../../src/canton/index.js";
8
8
  import { normalizeAssetId } from "../../src/canton/instrumentCatalog.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temple-digital-group/temple-canton-js",
3
- "version": "2.0.5",
3
+ "version": "2.0.6-beta-1",
4
4
  "description": "JavaScript library for interacting with Temple Canton blockchain",
5
5
  "type": "module",
6
6
  "main": "index.js",