@temple-digital-group/temple-canton-js 2.0.2 → 2.0.3-beta.0
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.
- package/README.md +457 -457
- package/index.js +15 -15
- package/package.json +49 -49
- package/src/api/config.d.ts +20 -20
- package/src/api/index.ts +322 -322
- package/src/api/tokenStore.ts +30 -30
- package/src/api/types.ts +196 -196
- package/src/auth0/index.d.ts +1 -1
- package/src/auth0/index.js +50 -50
- package/src/canton/deposits.ts +563 -563
- package/src/canton/helpers.ts +266 -266
- package/src/canton/index.d.ts +41 -41
- package/src/canton/index.js +3472 -3472
- package/src/canton/instrumentCatalog.d.ts +7 -7
- package/src/canton/instrumentCatalog.js +283 -283
- package/src/canton/request_schemas/cancel_orders_amulet.json +77 -77
- package/src/canton/request_schemas/cancel_orders_utility.json +68 -68
- package/src/canton/request_schemas/create_order_proposal_amulet.json +94 -94
- package/src/canton/request_schemas/create_order_proposal_utility.json +121 -121
- package/src/canton/request_schemas/create_utility_credential.json +31 -31
- package/src/canton/request_schemas/execute_transfer_factory.json +43 -43
- package/src/canton/request_schemas/get_allocation_factory.json +21 -21
- package/src/canton/request_schemas/get_amulet_holdings.json +21 -21
- package/src/canton/request_schemas/get_instrument_configurations.json +21 -21
- package/src/canton/request_schemas/get_locked_amulet_holdings.json +21 -21
- package/src/canton/request_schemas/get_order_proposals.json +21 -21
- package/src/canton/request_schemas/get_orders.json +21 -21
- package/src/canton/request_schemas/get_sender_credentials.json +22 -22
- package/src/canton/request_schemas/get_transfer_factory.json +28 -28
- package/src/canton/request_schemas/get_utility_holdings.json +21 -21
- package/src/canton/request_schemas/unlock_amulet.json +38 -38
- package/src/canton/walletAdapter.d.ts +7 -7
- package/src/canton/walletAdapter.js +112 -112
- package/src/canton/withdrawals.ts +511 -511
- package/src/config/index.d.ts +63 -63
- package/src/config/index.js +188 -188
- package/src/websocket/index.ts +341 -341
- package/src/websocket/ws.d.ts +24 -24
package/src/canton/helpers.ts
CHANGED
|
@@ -1,266 +1,266 @@
|
|
|
1
|
-
import config from "../../src/config/index.js";
|
|
2
|
-
import axios from "axios";
|
|
3
|
-
import { getJWTToken } from "../../src/auth0/index.js";
|
|
4
|
-
import { getAdapterProvider } from "../../src/canton/walletAdapter.js";
|
|
5
|
-
import { instrumentCatalog, normalizeAssetId } from "../../src/canton/instrumentCatalog.js";
|
|
6
|
-
|
|
7
|
-
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
export const DEFAULT_AMULET_CONTEXT_KEYS = {
|
|
10
|
-
amuletRules: "amulet-rules",
|
|
11
|
-
featuredAppRight: "featured-app-right",
|
|
12
|
-
openRound: "open-round",
|
|
13
|
-
expireLock: "expire-lock",
|
|
14
|
-
} as const;
|
|
15
|
-
|
|
16
|
-
export const DEFAULT_UTILITY_CONTEXT_KEYS = {
|
|
17
|
-
instrumentConfiguration: "instrument-configuration",
|
|
18
|
-
instrumentConfigurationPrefixed: "utility.digitalasset.com/instrument-configuration",
|
|
19
|
-
senderCredentials: "sender-credentials",
|
|
20
|
-
senderCredentialsPrefixed: "utility.digitalasset.com/sender-credentials",
|
|
21
|
-
receiverCredentials: "receiver-credentials",
|
|
22
|
-
receiverCredentialsPrefixed: "utility.digitalasset.com/receiver-credentials",
|
|
23
|
-
appRewardConfiguration: "app-reward-configuration",
|
|
24
|
-
appRewardConfigurationPrefixed: "utility.digitalasset.com/app-reward-configuration",
|
|
25
|
-
featuredAppRight: "featured-app-right",
|
|
26
|
-
featuredAppRightPrefixed: "utility.digitalasset.com/featured-app-right",
|
|
27
|
-
} as const;
|
|
28
|
-
|
|
29
|
-
export const LOCAL_VALIDATOR_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1", "0.0.0.0"]);
|
|
30
|
-
|
|
31
|
-
export const FORCE_LEDGER_METADATA: boolean =
|
|
32
|
-
typeof process !== "undefined" && process.env
|
|
33
|
-
? String(process.env.FORCE_LEDGER_METADATA || "").toLowerCase() === "true"
|
|
34
|
-
: false;
|
|
35
|
-
|
|
36
|
-
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
export interface DisclosedContract {
|
|
39
|
-
templateId: string | null;
|
|
40
|
-
contractId: string;
|
|
41
|
-
createdEventBlob: string;
|
|
42
|
-
synchronizerId: string | null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface LedgerCommand {
|
|
46
|
-
commands: unknown[];
|
|
47
|
-
commandId: string;
|
|
48
|
-
userId: string;
|
|
49
|
-
applicationId: string;
|
|
50
|
-
actAs: string[];
|
|
51
|
-
disclosedContracts: DisclosedContract[];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface ContractMetadata {
|
|
55
|
-
contractCid: string;
|
|
56
|
-
disclosureCid: string;
|
|
57
|
-
synchronizerId: string | null;
|
|
58
|
-
templateId?: string | null;
|
|
59
|
-
payload?: Record<string, unknown>;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface ActiveContractEntry {
|
|
63
|
-
contractEntry?: {
|
|
64
|
-
JsActiveContract?: {
|
|
65
|
-
createdEvent?: {
|
|
66
|
-
contractId?: string;
|
|
67
|
-
createdEventBlob?: string;
|
|
68
|
-
templateId?: string;
|
|
69
|
-
createArgument?: Record<string, unknown>;
|
|
70
|
-
};
|
|
71
|
-
synchronizerId?: string;
|
|
72
|
-
templateId?: string;
|
|
73
|
-
};
|
|
74
|
-
};
|
|
75
|
-
createdEvent?: Record<string, unknown>;
|
|
76
|
-
contractId?: string;
|
|
77
|
-
[key: string]: unknown;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// ─── Pure Utilities ──────────────────────────────────────────────────────────
|
|
81
|
-
|
|
82
|
-
/** Cross-platform UUID generation. */
|
|
83
|
-
export const randomUUID = (): string => {
|
|
84
|
-
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
85
|
-
return crypto.randomUUID();
|
|
86
|
-
}
|
|
87
|
-
if (typeof require !== "undefined") {
|
|
88
|
-
const nodeCrypto = require("crypto");
|
|
89
|
-
return nodeCrypto.randomUUID();
|
|
90
|
-
}
|
|
91
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
92
|
-
const r = (Math.random() * 16) | 0;
|
|
93
|
-
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
94
|
-
return v.toString(16);
|
|
95
|
-
});
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/** Check if a validator URL points to localhost. */
|
|
99
|
-
export function isLocalValidatorUrl(urlValue: string | undefined | null): boolean {
|
|
100
|
-
if (!urlValue) return false;
|
|
101
|
-
try {
|
|
102
|
-
const parsed = new URL(urlValue);
|
|
103
|
-
return LOCAL_VALIDATOR_HOSTNAMES.has(parsed.hostname.toLowerCase());
|
|
104
|
-
} catch {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Determine if ledger should be used for metadata resolution. */
|
|
110
|
-
export function shouldUseLedgerForMetadata(): boolean {
|
|
111
|
-
if (FORCE_LEDGER_METADATA) return true;
|
|
112
|
-
if (!config.VALIDATOR_API_URL) return false;
|
|
113
|
-
return isLocalValidatorUrl(config.VALIDATOR_API_URL);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Trim a contract ID string. */
|
|
117
|
-
export function normalizeContractId(value: unknown): unknown {
|
|
118
|
-
if (typeof value !== "string") return value;
|
|
119
|
-
return value.trim();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** Recursively normalize contract references in an object. */
|
|
123
|
-
export function normalizeContractReferences(value: unknown): unknown {
|
|
124
|
-
if (Array.isArray(value)) {
|
|
125
|
-
return value.map(normalizeContractReferences);
|
|
126
|
-
}
|
|
127
|
-
if (value && typeof value === "object") {
|
|
128
|
-
const normalized: Record<string, unknown> = {};
|
|
129
|
-
for (const [key, entryValue] of Object.entries(value)) {
|
|
130
|
-
if (typeof entryValue === "string") {
|
|
131
|
-
normalized[key] = entryValue;
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
normalized[key] = normalizeContractReferences(entryValue);
|
|
135
|
-
}
|
|
136
|
-
return normalized;
|
|
137
|
-
}
|
|
138
|
-
if (typeof value === "string") {
|
|
139
|
-
return normalizeContractId(value);
|
|
140
|
-
}
|
|
141
|
-
return value;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** Resolve provider: use the passed value, or fall back to the wallet adapter's provider. */
|
|
145
|
-
export function resolveProvider(provider: unknown): unknown {
|
|
146
|
-
return provider || getAdapterProvider() || null;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// ─── Instrument Catalog ──────────────────────────────────────────────────────
|
|
150
|
-
|
|
151
|
-
/** Resolve an instrument definition from the catalog. */
|
|
152
|
-
export function resolveInstrumentDefinition(assetId: string): Record<string, unknown> | null {
|
|
153
|
-
if (!assetId || typeof assetId !== "string") return null;
|
|
154
|
-
return (instrumentCatalog as Record<string, Record<string, unknown>>)[normalizeAssetId(assetId)] || null;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/** Get the registrar for a utility instrument from the catalog. */
|
|
158
|
-
export function getInstrumentRegistrar(assetId: string): string | null {
|
|
159
|
-
const definition = resolveInstrumentDefinition(assetId);
|
|
160
|
-
const networkDef = definition?.[config.NETWORK] as Record<string, unknown> | undefined;
|
|
161
|
-
return (networkDef?.registrar as string) || null;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// ─── Contract Helpers ────────────────────────────────────────────────────────
|
|
165
|
-
|
|
166
|
-
/** Extract active contracts from various ledger response shapes. */
|
|
167
|
-
export function unwrapActiveContracts(responseData: unknown): unknown[] {
|
|
168
|
-
if (!responseData) return [];
|
|
169
|
-
if (Array.isArray(responseData)) return responseData;
|
|
170
|
-
const data = responseData as Record<string, unknown>;
|
|
171
|
-
if (Array.isArray(data.activeContracts)) return data.activeContracts;
|
|
172
|
-
if (Array.isArray(data.result)) return data.result;
|
|
173
|
-
if (Array.isArray(data.contracts)) return data.contracts;
|
|
174
|
-
return [];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/** Find a disclosed contract by template ID suffix. */
|
|
178
|
-
export function findDisclosedContract(
|
|
179
|
-
disclosedContracts: DisclosedContract[],
|
|
180
|
-
templateSuffix: string,
|
|
181
|
-
): DisclosedContract | null {
|
|
182
|
-
if (!Array.isArray(disclosedContracts)) return null;
|
|
183
|
-
return (
|
|
184
|
-
disclosedContracts.find((contract) => {
|
|
185
|
-
const templateId = contract?.templateId ?? "";
|
|
186
|
-
return templateId.endsWith(`:${templateSuffix}`);
|
|
187
|
-
}) || null
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** Map an active contract entry to a metadata structure. */
|
|
192
|
-
export function mapActiveContractMetadata(entry: ActiveContractEntry): {
|
|
193
|
-
contractId: unknown;
|
|
194
|
-
createdEventBlob: string | undefined;
|
|
195
|
-
synchronizerId: string | undefined;
|
|
196
|
-
templateId: string | null;
|
|
197
|
-
payload: Record<string, unknown>;
|
|
198
|
-
} | null {
|
|
199
|
-
const createdEvent = entry?.contractEntry?.JsActiveContract?.createdEvent;
|
|
200
|
-
if (!createdEvent) return null;
|
|
201
|
-
return {
|
|
202
|
-
contractId: normalizeContractId(createdEvent.contractId),
|
|
203
|
-
createdEventBlob: createdEvent.createdEventBlob,
|
|
204
|
-
synchronizerId: entry.contractEntry?.JsActiveContract?.synchronizerId,
|
|
205
|
-
templateId: createdEvent.templateId || entry.contractEntry?.JsActiveContract?.templateId || null,
|
|
206
|
-
payload: createdEvent.createArgument || {},
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/** Convert a contract entry to metadata. */
|
|
211
|
-
export function toContractMetadata(entry: {
|
|
212
|
-
contractId?: unknown;
|
|
213
|
-
createdEventBlob?: string;
|
|
214
|
-
synchronizerId?: string;
|
|
215
|
-
payload?: Record<string, unknown>;
|
|
216
|
-
} | null): ContractMetadata | null {
|
|
217
|
-
if (!entry) return null;
|
|
218
|
-
return {
|
|
219
|
-
contractCid: entry.contractId as string,
|
|
220
|
-
disclosureCid: entry.createdEventBlob as string,
|
|
221
|
-
synchronizerId: entry.synchronizerId || null,
|
|
222
|
-
payload: entry.payload,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// ─── Disclosed Contracts ─────────────────────────────────────────────────────
|
|
227
|
-
|
|
228
|
-
/** Deduplicate disclosed contracts in a command by contractId. */
|
|
229
|
-
export function dedupeDisclosedContracts(command: LedgerCommand): void {
|
|
230
|
-
if (!command || !Array.isArray(command.disclosedContracts)) return;
|
|
231
|
-
|
|
232
|
-
const deduped: DisclosedContract[] = [];
|
|
233
|
-
const seen = new Set<string>();
|
|
234
|
-
for (const entry of command.disclosedContracts) {
|
|
235
|
-
if (!entry || !entry.contractId || !entry.createdEventBlob) continue;
|
|
236
|
-
if (seen.has(entry.contractId)) continue;
|
|
237
|
-
seen.add(entry.contractId);
|
|
238
|
-
deduped.push(entry);
|
|
239
|
-
}
|
|
240
|
-
command.disclosedContracts = deduped;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// ─── Ledger Helpers ──────────────────────────────────────────────────────────
|
|
244
|
-
|
|
245
|
-
/** Build HTTP headers with JWT authorization. */
|
|
246
|
-
export async function buildHeaders(): Promise<Record<string, string>> {
|
|
247
|
-
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
248
|
-
const token = config.JWT_TOKEN || (config.AUTH0_TOKEN_URL ? await getJWTToken() : null);
|
|
249
|
-
if (token) {
|
|
250
|
-
headers.Authorization = `Bearer ${token}`;
|
|
251
|
-
}
|
|
252
|
-
return headers;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/** Get the current ledger end offset. */
|
|
256
|
-
export async function getLedgerEnd(): Promise<string | null> {
|
|
257
|
-
const headers = await buildHeaders();
|
|
258
|
-
const url = `${config.VALIDATOR_API_URL}/v2/state/ledger-end`;
|
|
259
|
-
try {
|
|
260
|
-
const response = await axios.get(url, { headers });
|
|
261
|
-
return response.data.offset;
|
|
262
|
-
} catch (error) {
|
|
263
|
-
console.error(`Error fetching ledger end: ${error}`);
|
|
264
|
-
return null;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
1
|
+
import config from "../../src/config/index.js";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import { getJWTToken } from "../../src/auth0/index.js";
|
|
4
|
+
import { getAdapterProvider } from "../../src/canton/walletAdapter.js";
|
|
5
|
+
import { instrumentCatalog, normalizeAssetId } from "../../src/canton/instrumentCatalog.js";
|
|
6
|
+
|
|
7
|
+
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_AMULET_CONTEXT_KEYS = {
|
|
10
|
+
amuletRules: "amulet-rules",
|
|
11
|
+
featuredAppRight: "featured-app-right",
|
|
12
|
+
openRound: "open-round",
|
|
13
|
+
expireLock: "expire-lock",
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
export const DEFAULT_UTILITY_CONTEXT_KEYS = {
|
|
17
|
+
instrumentConfiguration: "instrument-configuration",
|
|
18
|
+
instrumentConfigurationPrefixed: "utility.digitalasset.com/instrument-configuration",
|
|
19
|
+
senderCredentials: "sender-credentials",
|
|
20
|
+
senderCredentialsPrefixed: "utility.digitalasset.com/sender-credentials",
|
|
21
|
+
receiverCredentials: "receiver-credentials",
|
|
22
|
+
receiverCredentialsPrefixed: "utility.digitalasset.com/receiver-credentials",
|
|
23
|
+
appRewardConfiguration: "app-reward-configuration",
|
|
24
|
+
appRewardConfigurationPrefixed: "utility.digitalasset.com/app-reward-configuration",
|
|
25
|
+
featuredAppRight: "featured-app-right",
|
|
26
|
+
featuredAppRightPrefixed: "utility.digitalasset.com/featured-app-right",
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
export const LOCAL_VALIDATOR_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1", "0.0.0.0"]);
|
|
30
|
+
|
|
31
|
+
export const FORCE_LEDGER_METADATA: boolean =
|
|
32
|
+
typeof process !== "undefined" && process.env
|
|
33
|
+
? String(process.env.FORCE_LEDGER_METADATA || "").toLowerCase() === "true"
|
|
34
|
+
: false;
|
|
35
|
+
|
|
36
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export interface DisclosedContract {
|
|
39
|
+
templateId: string | null;
|
|
40
|
+
contractId: string;
|
|
41
|
+
createdEventBlob: string;
|
|
42
|
+
synchronizerId: string | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface LedgerCommand {
|
|
46
|
+
commands: unknown[];
|
|
47
|
+
commandId: string;
|
|
48
|
+
userId: string;
|
|
49
|
+
applicationId: string;
|
|
50
|
+
actAs: string[];
|
|
51
|
+
disclosedContracts: DisclosedContract[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ContractMetadata {
|
|
55
|
+
contractCid: string;
|
|
56
|
+
disclosureCid: string;
|
|
57
|
+
synchronizerId: string | null;
|
|
58
|
+
templateId?: string | null;
|
|
59
|
+
payload?: Record<string, unknown>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ActiveContractEntry {
|
|
63
|
+
contractEntry?: {
|
|
64
|
+
JsActiveContract?: {
|
|
65
|
+
createdEvent?: {
|
|
66
|
+
contractId?: string;
|
|
67
|
+
createdEventBlob?: string;
|
|
68
|
+
templateId?: string;
|
|
69
|
+
createArgument?: Record<string, unknown>;
|
|
70
|
+
};
|
|
71
|
+
synchronizerId?: string;
|
|
72
|
+
templateId?: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
createdEvent?: Record<string, unknown>;
|
|
76
|
+
contractId?: string;
|
|
77
|
+
[key: string]: unknown;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─── Pure Utilities ──────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
/** Cross-platform UUID generation. */
|
|
83
|
+
export const randomUUID = (): string => {
|
|
84
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
85
|
+
return crypto.randomUUID();
|
|
86
|
+
}
|
|
87
|
+
if (typeof require !== "undefined") {
|
|
88
|
+
const nodeCrypto = require("crypto");
|
|
89
|
+
return nodeCrypto.randomUUID();
|
|
90
|
+
}
|
|
91
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
92
|
+
const r = (Math.random() * 16) | 0;
|
|
93
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
94
|
+
return v.toString(16);
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** Check if a validator URL points to localhost. */
|
|
99
|
+
export function isLocalValidatorUrl(urlValue: string | undefined | null): boolean {
|
|
100
|
+
if (!urlValue) return false;
|
|
101
|
+
try {
|
|
102
|
+
const parsed = new URL(urlValue);
|
|
103
|
+
return LOCAL_VALIDATOR_HOSTNAMES.has(parsed.hostname.toLowerCase());
|
|
104
|
+
} catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Determine if ledger should be used for metadata resolution. */
|
|
110
|
+
export function shouldUseLedgerForMetadata(): boolean {
|
|
111
|
+
if (FORCE_LEDGER_METADATA) return true;
|
|
112
|
+
if (!config.VALIDATOR_API_URL) return false;
|
|
113
|
+
return isLocalValidatorUrl(config.VALIDATOR_API_URL);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Trim a contract ID string. */
|
|
117
|
+
export function normalizeContractId(value: unknown): unknown {
|
|
118
|
+
if (typeof value !== "string") return value;
|
|
119
|
+
return value.trim();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Recursively normalize contract references in an object. */
|
|
123
|
+
export function normalizeContractReferences(value: unknown): unknown {
|
|
124
|
+
if (Array.isArray(value)) {
|
|
125
|
+
return value.map(normalizeContractReferences);
|
|
126
|
+
}
|
|
127
|
+
if (value && typeof value === "object") {
|
|
128
|
+
const normalized: Record<string, unknown> = {};
|
|
129
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
130
|
+
if (typeof entryValue === "string") {
|
|
131
|
+
normalized[key] = entryValue;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
normalized[key] = normalizeContractReferences(entryValue);
|
|
135
|
+
}
|
|
136
|
+
return normalized;
|
|
137
|
+
}
|
|
138
|
+
if (typeof value === "string") {
|
|
139
|
+
return normalizeContractId(value);
|
|
140
|
+
}
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Resolve provider: use the passed value, or fall back to the wallet adapter's provider. */
|
|
145
|
+
export function resolveProvider(provider: unknown): unknown {
|
|
146
|
+
return provider || getAdapterProvider() || null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ─── Instrument Catalog ──────────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
/** Resolve an instrument definition from the catalog. */
|
|
152
|
+
export function resolveInstrumentDefinition(assetId: string): Record<string, unknown> | null {
|
|
153
|
+
if (!assetId || typeof assetId !== "string") return null;
|
|
154
|
+
return (instrumentCatalog as Record<string, Record<string, unknown>>)[normalizeAssetId(assetId)] || null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Get the registrar for a utility instrument from the catalog. */
|
|
158
|
+
export function getInstrumentRegistrar(assetId: string): string | null {
|
|
159
|
+
const definition = resolveInstrumentDefinition(assetId);
|
|
160
|
+
const networkDef = definition?.[config.NETWORK] as Record<string, unknown> | undefined;
|
|
161
|
+
return (networkDef?.registrar as string) || null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ─── Contract Helpers ────────────────────────────────────────────────────────
|
|
165
|
+
|
|
166
|
+
/** Extract active contracts from various ledger response shapes. */
|
|
167
|
+
export function unwrapActiveContracts(responseData: unknown): unknown[] {
|
|
168
|
+
if (!responseData) return [];
|
|
169
|
+
if (Array.isArray(responseData)) return responseData;
|
|
170
|
+
const data = responseData as Record<string, unknown>;
|
|
171
|
+
if (Array.isArray(data.activeContracts)) return data.activeContracts;
|
|
172
|
+
if (Array.isArray(data.result)) return data.result;
|
|
173
|
+
if (Array.isArray(data.contracts)) return data.contracts;
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Find a disclosed contract by template ID suffix. */
|
|
178
|
+
export function findDisclosedContract(
|
|
179
|
+
disclosedContracts: DisclosedContract[],
|
|
180
|
+
templateSuffix: string,
|
|
181
|
+
): DisclosedContract | null {
|
|
182
|
+
if (!Array.isArray(disclosedContracts)) return null;
|
|
183
|
+
return (
|
|
184
|
+
disclosedContracts.find((contract) => {
|
|
185
|
+
const templateId = contract?.templateId ?? "";
|
|
186
|
+
return templateId.endsWith(`:${templateSuffix}`);
|
|
187
|
+
}) || null
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Map an active contract entry to a metadata structure. */
|
|
192
|
+
export function mapActiveContractMetadata(entry: ActiveContractEntry): {
|
|
193
|
+
contractId: unknown;
|
|
194
|
+
createdEventBlob: string | undefined;
|
|
195
|
+
synchronizerId: string | undefined;
|
|
196
|
+
templateId: string | null;
|
|
197
|
+
payload: Record<string, unknown>;
|
|
198
|
+
} | null {
|
|
199
|
+
const createdEvent = entry?.contractEntry?.JsActiveContract?.createdEvent;
|
|
200
|
+
if (!createdEvent) return null;
|
|
201
|
+
return {
|
|
202
|
+
contractId: normalizeContractId(createdEvent.contractId),
|
|
203
|
+
createdEventBlob: createdEvent.createdEventBlob,
|
|
204
|
+
synchronizerId: entry.contractEntry?.JsActiveContract?.synchronizerId,
|
|
205
|
+
templateId: createdEvent.templateId || entry.contractEntry?.JsActiveContract?.templateId || null,
|
|
206
|
+
payload: createdEvent.createArgument || {},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Convert a contract entry to metadata. */
|
|
211
|
+
export function toContractMetadata(entry: {
|
|
212
|
+
contractId?: unknown;
|
|
213
|
+
createdEventBlob?: string;
|
|
214
|
+
synchronizerId?: string;
|
|
215
|
+
payload?: Record<string, unknown>;
|
|
216
|
+
} | null): ContractMetadata | null {
|
|
217
|
+
if (!entry) return null;
|
|
218
|
+
return {
|
|
219
|
+
contractCid: entry.contractId as string,
|
|
220
|
+
disclosureCid: entry.createdEventBlob as string,
|
|
221
|
+
synchronizerId: entry.synchronizerId || null,
|
|
222
|
+
payload: entry.payload,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ─── Disclosed Contracts ─────────────────────────────────────────────────────
|
|
227
|
+
|
|
228
|
+
/** Deduplicate disclosed contracts in a command by contractId. */
|
|
229
|
+
export function dedupeDisclosedContracts(command: LedgerCommand): void {
|
|
230
|
+
if (!command || !Array.isArray(command.disclosedContracts)) return;
|
|
231
|
+
|
|
232
|
+
const deduped: DisclosedContract[] = [];
|
|
233
|
+
const seen = new Set<string>();
|
|
234
|
+
for (const entry of command.disclosedContracts) {
|
|
235
|
+
if (!entry || !entry.contractId || !entry.createdEventBlob) continue;
|
|
236
|
+
if (seen.has(entry.contractId)) continue;
|
|
237
|
+
seen.add(entry.contractId);
|
|
238
|
+
deduped.push(entry);
|
|
239
|
+
}
|
|
240
|
+
command.disclosedContracts = deduped;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ─── Ledger Helpers ──────────────────────────────────────────────────────────
|
|
244
|
+
|
|
245
|
+
/** Build HTTP headers with JWT authorization. */
|
|
246
|
+
export async function buildHeaders(): Promise<Record<string, string>> {
|
|
247
|
+
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
248
|
+
const token = config.JWT_TOKEN || (config.AUTH0_TOKEN_URL ? await getJWTToken() : null);
|
|
249
|
+
if (token) {
|
|
250
|
+
headers.Authorization = `Bearer ${token}`;
|
|
251
|
+
}
|
|
252
|
+
return headers;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Get the current ledger end offset. */
|
|
256
|
+
export async function getLedgerEnd(): Promise<string | null> {
|
|
257
|
+
const headers = await buildHeaders();
|
|
258
|
+
const url = `${config.VALIDATOR_API_URL}/v2/state/ledger-end`;
|
|
259
|
+
try {
|
|
260
|
+
const response = await axios.get(url, { headers });
|
|
261
|
+
return response.data.offset;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error(`Error fetching ledger end: ${error}`);
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
package/src/canton/index.d.ts
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import type { ContractMetadata } from "./helpers.js";
|
|
2
|
-
|
|
3
|
-
export function resolveAmuletContext(opts: {
|
|
4
|
-
investor: string;
|
|
5
|
-
holdingIds?: string[];
|
|
6
|
-
transferAmount?: number;
|
|
7
|
-
}): Promise<Record<string, unknown> | null>;
|
|
8
|
-
|
|
9
|
-
export function resolveUtilityInstrumentConfiguration(
|
|
10
|
-
utilityAsset: string,
|
|
11
|
-
registrar: string | null,
|
|
12
|
-
): Promise<ContractMetadata | null>;
|
|
13
|
-
|
|
14
|
-
export function resolveUtilityAllocationFactory(
|
|
15
|
-
registrar: string,
|
|
16
|
-
holder?: string | null,
|
|
17
|
-
): Promise<ContractMetadata | null>;
|
|
18
|
-
|
|
19
|
-
export function getAmuletHoldingsForParty(
|
|
20
|
-
party: string,
|
|
21
|
-
returnCommand?: boolean,
|
|
22
|
-
provider?: unknown,
|
|
23
|
-
): Promise<unknown[]>;
|
|
24
|
-
|
|
25
|
-
export function getUtilityHoldingsForParty(
|
|
26
|
-
party: string,
|
|
27
|
-
returnCommand?: boolean,
|
|
28
|
-
provider?: unknown,
|
|
29
|
-
): Promise<unknown[]>;
|
|
30
|
-
|
|
31
|
-
export function getUtxoCount(
|
|
32
|
-
party: string,
|
|
33
|
-
assetId: string,
|
|
34
|
-
provider?: unknown,
|
|
35
|
-
): Promise<{
|
|
36
|
-
total: number;
|
|
37
|
-
unlocked: number;
|
|
38
|
-
locked: number;
|
|
39
|
-
largestUnlocked: number;
|
|
40
|
-
unlockedBalance: number;
|
|
41
|
-
}>;
|
|
1
|
+
import type { ContractMetadata } from "./helpers.js";
|
|
2
|
+
|
|
3
|
+
export function resolveAmuletContext(opts: {
|
|
4
|
+
investor: string;
|
|
5
|
+
holdingIds?: string[];
|
|
6
|
+
transferAmount?: number;
|
|
7
|
+
}): Promise<Record<string, unknown> | null>;
|
|
8
|
+
|
|
9
|
+
export function resolveUtilityInstrumentConfiguration(
|
|
10
|
+
utilityAsset: string,
|
|
11
|
+
registrar: string | null,
|
|
12
|
+
): Promise<ContractMetadata | null>;
|
|
13
|
+
|
|
14
|
+
export function resolveUtilityAllocationFactory(
|
|
15
|
+
registrar: string,
|
|
16
|
+
holder?: string | null,
|
|
17
|
+
): Promise<ContractMetadata | null>;
|
|
18
|
+
|
|
19
|
+
export function getAmuletHoldingsForParty(
|
|
20
|
+
party: string,
|
|
21
|
+
returnCommand?: boolean,
|
|
22
|
+
provider?: unknown,
|
|
23
|
+
): Promise<unknown[]>;
|
|
24
|
+
|
|
25
|
+
export function getUtilityHoldingsForParty(
|
|
26
|
+
party: string,
|
|
27
|
+
returnCommand?: boolean,
|
|
28
|
+
provider?: unknown,
|
|
29
|
+
): Promise<unknown[]>;
|
|
30
|
+
|
|
31
|
+
export function getUtxoCount(
|
|
32
|
+
party: string,
|
|
33
|
+
assetId: string,
|
|
34
|
+
provider?: unknown,
|
|
35
|
+
): Promise<{
|
|
36
|
+
total: number;
|
|
37
|
+
unlocked: number;
|
|
38
|
+
locked: number;
|
|
39
|
+
largestUnlocked: number;
|
|
40
|
+
unlockedBalance: number;
|
|
41
|
+
}>;
|