@layerzerolabs/common-canton 0.2.103 → 0.2.105

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layerzerolabs/common-canton",
3
- "version": "0.2.103",
3
+ "version": "0.2.105",
4
4
  "private": false,
5
5
  "description": "Canton VM client and utilities",
6
6
  "license": "MIT",
@@ -21,8 +21,8 @@
21
21
  "@protobuf-ts/grpc-transport": "^2.9.4",
22
22
  "es-toolkit": "^1.39.10",
23
23
  "zod": "4.3.5",
24
- "@layerzerolabs/common-chain-model": "0.2.103",
25
- "@layerzerolabs/typescript-utils": "0.2.103"
24
+ "@layerzerolabs/typescript-utils": "0.2.105",
25
+ "@layerzerolabs/common-chain-model": "0.2.105"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.18.6",
@@ -31,12 +31,12 @@
31
31
  "tsup": "^8.4.0",
32
32
  "typescript": "^5.8.2",
33
33
  "vitest": "^3.2.3",
34
- "@layerzerolabs/eslint-configuration": "^0.2.103",
35
- "@layerzerolabs/tsup-configuration": "0.2.103",
36
- "@layerzerolabs/typescript-configuration": "0.2.103",
37
- "@layerzerolabs/ver-signer-adapter": "0.2.103",
38
- "@layerzerolabs/vm-tooling-canton": "0.2.103",
39
- "@layerzerolabs/vitest-configuration": "0.2.103"
34
+ "@layerzerolabs/typescript-configuration": "0.2.105",
35
+ "@layerzerolabs/tsup-configuration": "0.2.105",
36
+ "@layerzerolabs/eslint-configuration": "^0.2.105",
37
+ "@layerzerolabs/ver-signer-adapter": "0.2.105",
38
+ "@layerzerolabs/vitest-configuration": "0.2.105",
39
+ "@layerzerolabs/vm-tooling-canton": "0.2.105"
40
40
  },
41
41
  "publishConfig": {
42
42
  "access": "restricted",
package/src/provider.ts CHANGED
@@ -24,8 +24,9 @@ export type CantonProvider = {
24
24
  client: ICantonClient;
25
25
  grpcClient: CantonGrpcClient;
26
26
  tokenProvider: TokenProvider;
27
- /** Validator wallet URL for scan-proxy CIP-56 endpoints. */
28
- walletUrl?: string;
27
+ /** Validator wallet URL for scan-proxy CIP-56 endpoints. Required — amulet fee
28
+ * payment needs it on every Canton transaction; enforced in {@link parseCantonUri}. */
29
+ walletUrl: string;
29
30
  };
30
31
 
31
32
  // ─────────────────────────────────────────────────────────────────────────────
@@ -40,7 +41,7 @@ export type CantonUriParams = {
40
41
  /** Ledger API user ID (default: "participant_admin") */
41
42
  userId: string;
42
43
  /** Validator wallet URL for scan-proxy CIP-56 endpoints (e.g. "http://localhost:7201") */
43
- walletUrl?: string;
44
+ walletUrl: string;
44
45
  /** OAuth2 client credentials config — present only for non-local environments */
45
46
  oauth2?: ClientCredentialsTokenProviderConfig;
46
47
  };
@@ -66,7 +67,14 @@ export function parseCantonUri(uri: string): CantonUriParams {
66
67
  }
67
68
 
68
69
  const userId = url.searchParams.get('user-id') ?? 'participant_admin';
69
- const walletUrl = url.searchParams.get('wallet-url') ?? undefined;
70
+
71
+ // Required: amulet fee payment hits the validator wallet scan-proxy on every
72
+ // Canton transaction, so a provider without it can't transact. Fail at parse
73
+ // time rather than guarding each downstream use.
74
+ const walletUrl = url.searchParams.get('wallet-url');
75
+ if (!walletUrl) {
76
+ throw new Error('Canton provider URI missing required "wallet-url" query parameter');
77
+ }
70
78
  const tokenUrl = url.searchParams.get('token-url') ?? undefined;
71
79
  const clientId = url.searchParams.get('client-id') ?? undefined;
72
80
  const clientSecret = url.searchParams.get('client-secret') ?? undefined;
@@ -90,3 +90,30 @@ export const replaceCantonAmuletCidsPlaceholder = <T>(value: T, amuletCids: stri
90
90
  visit(value, (leaf) =>
91
91
  isAmuletCidsPlaceholderArray(leaf) ? { value: amuletCids } : undefined,
92
92
  );
93
+
94
+ /** Sentinel for a choice's `extraArgs.context`, replaced with the freshly-fetched
95
+ * amulet choice context at sign time. */
96
+ export const CANTON_AMULET_CONTEXT_PLACEHOLDER = '<<CANTON_AMULET_CONTEXT_PLACEHOLDER>>';
97
+
98
+ /** Sentinel for the exercised ExternalPartyAmuletRules contract id, re-pinned to the
99
+ * freshly-fetched amulet fee bundle at sign time. */
100
+ export const CANTON_AMULET_RULES_CID_PLACEHOLDER = '<<CANTON_AMULET_RULES_CID_PLACEHOLDER>>';
101
+
102
+ // ─────────────────────────────────────────────────────────────────────────────
103
+ // Generic placeholder helpers (sentinel-agnostic)
104
+ //
105
+ // Used by the sign-time refresh executor, which receives the sentinel to match as
106
+ // data (from the transaction's refreshSpec, or a known amulet sentinel) instead of
107
+ // hardcoding it here — keeping these helpers free of any contract knowledge.
108
+ // ─────────────────────────────────────────────────────────────────────────────
109
+
110
+ /** Returns true if any scalar leaf in the tree equals `placeholder`. */
111
+ export const containsPlaceholderValue = (value: unknown, placeholder: string): boolean =>
112
+ containsLeaf(value, (leaf) => leaf === placeholder);
113
+
114
+ /** Replace every scalar sentinel leaf equal to `placeholder` with `replacement`. */
115
+ export const replacePlaceholderValue = <T>(
116
+ value: T,
117
+ placeholder: string,
118
+ replacement: unknown,
119
+ ): T => visit(value, (leaf) => (leaf === placeholder ? { value: replacement } : undefined));
@@ -53,6 +53,41 @@ export const cantonDisclosedContractSchema = z.object({
53
53
  synchronizerId: z.string(),
54
54
  });
55
55
 
56
+ /** A contract located by an Active Contract Set query, run as a party that can see
57
+ * it (the sender for holdings; a config admin for OFT/RequestFactory/… later). */
58
+ const ledgerRefreshEntrySchema = z.object({
59
+ /** Party whose Active Contract Set to query; resolved at sign time. */
60
+ partyToFilter: z.literal('sender'),
61
+ /** Template id to query. */
62
+ templateId: z.string(),
63
+ });
64
+
65
+ /**
66
+ * Declarative description of ledger contracts the building factory deferred to sign
67
+ * time, resolved by a generic ledger-query refresh executor. (The amulet fee context is
68
+ * refreshed automatically when a command carries its placeholder, so it isn't declared
69
+ * here.)
70
+ */
71
+ export const cantonRefreshSpecSchema = z.object({
72
+ /** Command-tree placeholders, each replaced with the contract id(s) from a ledger query. */
73
+ commands: z
74
+ .array(
75
+ ledgerRefreshEntrySchema.extend({
76
+ /** Sentinel to replace in the command tree. */
77
+ placeholder: z.string(),
78
+ /** When true, the placeholder is replaced with the full array of resolved
79
+ * contract ids (e.g. amulet holdings); otherwise with the single id. */
80
+ multiple: z.boolean().optional(),
81
+ }),
82
+ )
83
+ .optional(),
84
+ /** Contracts fetched via a ledger query (run as the sender) and appended to
85
+ * disclosedContracts. */
86
+ disclosedContracts: z.array(ledgerRefreshEntrySchema).optional(),
87
+ });
88
+
89
+ export type CantonRefreshSpec = z.infer<typeof cantonRefreshSpecSchema>;
90
+
56
91
  /** Output of prepareForSigning — needed by submitSigned to execute the transaction. */
57
92
  const cantonInflightTransactionSchema = z.object({
58
93
  /** The prepared transaction blob */
@@ -88,10 +123,16 @@ export const cantonTransactionSchema = transactionSchema.extend({
88
123
  commands: z.array(cantonCommandSchema),
89
124
  /** Disclosed contracts for contract/key lookups */
90
125
  disclosedContracts: z.array(cantonDisclosedContractSchema),
91
- /** Maps each `actAs` party ID → the senderEntityName that controls its
92
- * signing key. Optional in the schema, but must be populated and cover
93
- * every `actAs` party before the transaction can be signed. */
94
- partyToSenderEntity: z.record(z.string(), z.string()).optional(),
126
+ /** Maps each actAs party → the senderEntityName(s) controlling its signing
127
+ * key(s), always as an array. `.optional()` only so deferred-sender create-time
128
+ * payloads parse; by sign time every actAs party must map, or signing throws.
129
+ * Multiple entries = a multisig party (decentralized namespace) whose keys must
130
+ * all sign. */
131
+ partyToSenderEntity: z.record(z.string(), z.array(z.string())).optional(),
132
+ /** Sign-time refresh spec for placeholders the building factory deferred
133
+ * (e.g. amulet input holdings, disclosures, time-sensitive choice context).
134
+ * Resolved by the generic refresh executor before prepareForSigning. */
135
+ refreshSpec: cantonRefreshSpecSchema.optional(),
95
136
  }),
96
137
  });
97
138
 
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/senderPlaceholder.ts"],"names":["visit","value","replace","result","Array","isArray","map","item","mapValues","containsLeaf","predicate","some","Object","values","CANTON_SENDER_PLACEHOLDER","isCantonSenderPlaceholder","replaceCantonSenderPlaceholders","senderParty","leaf","undefined","containsCantonSenderPlaceholder","CANTON_AMULET_CIDS_PLACEHOLDER","isAmuletCidsPlaceholderArray","length","containsCantonAmuletCidsPlaceholder","replaceCantonAmuletCidsPlaceholder","amuletCids"],"mappings":";;;AAaA,IAAMA,KAAAA,mBAAQ,MAAA,CAAA,CAAIC,KAAAA,EAAUC,OAAAA,KAAAA;AACxB,EAAA,MAAMC,MAAAA,GAASD,QAAQD,KAAAA,CAAAA;AACvB,EAAA,IAAIE,MAAAA,SAAeA,MAAAA,CAAOF,KAAAA;AAC1B,EAAA,IAAIG,KAAAA,CAAMC,OAAAA,CAAQJ,KAAAA,CAAAA,EAAQ;AACtB,IAAA,OAAOA,MAAMK,GAAAA,CAAI,CAACC,SAASP,KAAAA,CAAMO,IAAAA,EAAML,OAAAA,CAAAA,CAAAA;AAC3C,EAAA;AACA,EAAA,IAAID,KAAAA,KAAU,IAAA,IAAQ,OAAOA,KAAAA,KAAU,QAAA,EAAU;AAC7C,IAAA,OAAOO,UAAUP,KAAAA,EAAkC,CAACM,SAASP,KAAAA,CAAMO,IAAAA,EAAML,OAAAA,CAAAA,CAAAA;AAC7E,EAAA;AACA,EAAA,OAAOD,KAAAA;AACX,CAAA,EAVc,OAAA,CAAA;AAad,IAAMQ,YAAAA,mBAAe,MAAA,CAAA,CAACR,KAAAA,EAAgBS,SAAAA,KAAAA;AAClC,EAAA,IAAIA,SAAAA,CAAUT,KAAAA,CAAAA,EAAQ,OAAO,IAAA;AAC7B,EAAA,IAAIG,KAAAA,CAAMC,OAAAA,CAAQJ,KAAAA,CAAAA,EAAQ,OAAOA,KAAAA,CAAMU,IAAAA,CAAK,CAACJ,IAAAA,KAASE,YAAAA,CAAaF,IAAAA,EAAMG,SAAAA,CAAAA,CAAAA;AACzE,EAAA,OACIT,KAAAA,KAAU,IAAA,IACV,OAAOA,KAAAA,KAAU,YACjBW,MAAAA,CAAOC,MAAAA,CAAOZ,KAAAA,CAAAA,CAAOU,KAAK,CAACJ,IAAAA,KAASE,YAAAA,CAAaF,IAAAA,EAAMG,SAAAA,CAAAA,CAAAA;AAE/D,CAAA,EARqB,cAAA,CAAA;AAkBd,IAAMI,yBAAAA,GAA4B;AAKlC,IAAMC,yBAAAA,mBAA4B,MAAA,CAAA,CAACd,KAAAA,KACtCA,KAAAA,KAAUa,yBAAAA,EAD2B,2BAAA;AAIlC,IAAME,+BAAAA,2BAAsCf,KAAAA,EAAUgB,WAAAA,KACzDjB,MAAMC,KAAAA,EAAO,CAACiB,IAAAA,KACVA,IAAAA,KAASJ,yBAAAA,GAA4B;EAAEb,KAAAA,EAAOgB;AAAY,CAAA,GAAIE,MAAAA,CAAAA,EAFvB,iCAAA;AAMxC,IAAMC,+BAAAA,2BAAmCnB,KAAAA,KAC5CQ,YAAAA,CAAaR,OAAO,CAACiB,IAAAA,KAASA,IAAAA,KAASJ,yBAAAA,CAAAA,EADI,iCAAA;AAYxC,IAAMO,8BAAAA,GAAiC;AAE9C,IAAMC,4BAAAA,mBAA+B,MAAA,CAAA,CAACrB,KAAAA,KAClCG,KAAAA,CAAMC,OAAAA,CAAQJ,KAAAA,CAAAA,IAAUA,KAAAA,CAAMsB,MAAAA,KAAW,CAAA,IAAKtB,KAAAA,CAAM,CAAA,MAAOoB,8BAAAA,EAD1B,8BAAA,CAAA;AAO9B,IAAMG,sDAAsC,MAAA,CAAA,CAACvB,KAAAA,KAChDQ,YAAAA,CAAaR,KAAAA,EAAOqB,4BAAAA,CAAAA,EAD2B,qCAAA;AAQ5C,IAAMG,kCAAAA,mBAAqC,MAAA,CAAA,CAAIxB,KAAAA,EAAUyB,UAAAA,KAC5D1B,KAAAA,CAAMC,OAAO,CAACiB,IAAAA,KACVI,4BAAAA,CAA6BJ,IAAAA,CAAAA,GAAQ;EAAEjB,KAAAA,EAAOyB;AAAW,CAAA,GAAIP,MAAAA,CAAAA,EAFnB,oCAAA","file":"6VTJWUC7.js","sourcesContent":["import { mapValues } from 'es-toolkit';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Generic JSON-tree visitors\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Result of a leaf check: either the leaf has been replaced (with `value`),\n * or `undefined` to leave it alone and recurse into its children.\n */\ntype LeafResult = { value: unknown } | undefined;\n\n/** Walk a JSON value and rewrite leaves matched by `replace`; recursion stops at a swapped leaf. */\nconst visit = <T>(value: T, replace: (leaf: unknown) => LeafResult): T => {\n const result = replace(value);\n if (result) return result.value as T;\n if (Array.isArray(value)) {\n return value.map((item) => visit(item, replace)) as T;\n }\n if (value !== null && typeof value === 'object') {\n return mapValues(value as Record<string, unknown>, (item) => visit(item, replace)) as T;\n }\n return value;\n};\n\n/** True if `predicate` matches any leaf or sub-value in the tree. */\nconst containsLeaf = (value: unknown, predicate: (leaf: unknown) => boolean): boolean => {\n if (predicate(value)) return true;\n if (Array.isArray(value)) return value.some((item) => containsLeaf(item, predicate));\n return (\n value !== null &&\n typeof value === 'object' &&\n Object.values(value).some((item) => containsLeaf(item, predicate))\n );\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Sender placeholder\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Sentinel emitted in place of the sender `Party` when the sender is unknown at\n * create time; substituted for the real party at sign time.\n */\nexport const CANTON_SENDER_PLACEHOLDER = '<<CANTON_SENDER_PLACEHOLDER>>';\n\n/**\n * Returns true if `value` is the Canton sender placeholder.\n */\nexport const isCantonSenderPlaceholder = (value: string): boolean =>\n value === CANTON_SENDER_PLACEHOLDER;\n\n/** Replace every {@link CANTON_SENDER_PLACEHOLDER} in a command tree with the actual sender party ID. */\nexport const replaceCantonSenderPlaceholders = <T>(value: T, senderParty: string): T =>\n visit(value, (leaf) =>\n leaf === CANTON_SENDER_PLACEHOLDER ? { value: senderParty } : undefined,\n );\n\n/** Returns true if the command tree contains the sender placeholder anywhere. */\nexport const containsCantonSenderPlaceholder = (value: unknown): boolean =>\n containsLeaf(value, (leaf) => leaf === CANTON_SENDER_PLACEHOLDER);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// AmuletCids placeholder\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Sentinel emitted as the sole element of the `amuletCids` array\n * (`amuletCids: [CANTON_AMULET_CIDS_PLACEHOLDER]`); substituted for the resolved\n * sender's Amulet contract IDs at sign time.\n */\nexport const CANTON_AMULET_CIDS_PLACEHOLDER = '<<CANTON_AMULET_CIDS_PLACEHOLDER>>';\n\nconst isAmuletCidsPlaceholderArray = (value: unknown): value is [string] =>\n Array.isArray(value) && value.length === 1 && value[0] === CANTON_AMULET_CIDS_PLACEHOLDER;\n\n/**\n * Returns true if the command tree contains an amulet-cids placeholder array\n * anywhere — i.e. an array `[CANTON_AMULET_CIDS_PLACEHOLDER]`.\n */\nexport const containsCantonAmuletCidsPlaceholder = (value: unknown): boolean =>\n containsLeaf(value, isAmuletCidsPlaceholderArray);\n\n/**\n * Recursively walks a JSON-serializable value and replaces every\n * `[CANTON_AMULET_CIDS_PLACEHOLDER]` array with the supplied list of resolved\n * Amulet contract IDs.\n */\nexport const replaceCantonAmuletCidsPlaceholder = <T>(value: T, amuletCids: string[]): T =>\n visit(value, (leaf) =>\n isAmuletCidsPlaceholderArray(leaf) ? { value: amuletCids } : undefined,\n );\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/transaction.ts"],"names":["createCommandSchema","z","object","templateId","string","createArguments","any","exerciseCommandSchema","contractId","choice","choiceArgument","createAndExerciseCommandSchema","exerciseByKeyCommandSchema","contractKey","cantonCommandSchema","union","createCommand","exerciseCommand","createAndExerciseCommand","exerciseByKeyCommand","cantonDisclosedContractSchema","optional","createdEventBlob","synchronizerId","cantonInflightTransactionSchema","preparedTransaction","preparedTransactionHash","hashingSchemeVersion","enum","commandId","completionOffset","number","cantonTransactionSchema","transactionSchema","extend","populatedTransaction","actAs","array","commands","disclosedContracts","partyToSenderEntity","record","cantonAssignedTransactionSchema","assignedTransactionSchema","shape","inflightTransaction","cantonSignedTransactionSchema","signedTransactionSchema","signedTransaction","signatures","party","format","signature","signedBy","signingAlgorithmSpec","cantonMinedTransactionSchema","minedTransactionSchema","buildCantonTransaction","chainName","tx","timestamps","created","Date","now"],"mappings":"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","file":"7G32CZXC.js","sourcesContent":["import { z } from 'zod';\n\nimport {\n assignedTransactionSchema,\n minedTransactionSchema,\n signedTransactionSchema,\n transactionSchema,\n} from '@layerzerolabs/common-chain-model';\nimport type { PartialBy } from '@layerzerolabs/typescript-utils';\n\n// === Component schemas ===\n\n// Payload fields (createArguments, choiceArgument, contractKey) are z.any() —\n// arbitrary Daml values whose shape depends on the template.\n\nconst createCommandSchema = z.object({\n templateId: z.string(),\n createArguments: z.any(),\n});\n\nconst exerciseCommandSchema = z.object({\n templateId: z.string(),\n contractId: z.string(),\n choice: z.string(),\n choiceArgument: z.any(),\n});\n\nconst createAndExerciseCommandSchema = z.object({\n templateId: z.string(),\n createArguments: z.any(),\n choice: z.string(),\n choiceArgument: z.any(),\n});\n\nconst exerciseByKeyCommandSchema = z.object({\n templateId: z.string(),\n contractKey: z.any(),\n choice: z.string(),\n choiceArgument: z.any(),\n});\n\nexport const cantonCommandSchema = z.union([\n z.object({ createCommand: createCommandSchema }),\n z.object({ exerciseCommand: exerciseCommandSchema }),\n z.object({ createAndExerciseCommand: createAndExerciseCommandSchema }),\n z.object({ exerciseByKeyCommand: exerciseByKeyCommandSchema }),\n]);\n\nexport const cantonDisclosedContractSchema = z.object({\n templateId: z.string().optional(),\n contractId: z.string(),\n createdEventBlob: z.string(),\n synchronizerId: z.string(),\n});\n\n/** Output of prepareForSigning — needed by submitSigned to execute the transaction. */\nconst cantonInflightTransactionSchema = z.object({\n /** The prepared transaction blob */\n preparedTransaction: z.string(),\n /** Hash of the prepared transaction (what was signed) */\n preparedTransactionHash: z.string(),\n /** Hashing scheme version used */\n hashingSchemeVersion: z.enum([\n 'HASHING_SCHEME_VERSION_UNSPECIFIED',\n 'HASHING_SCHEME_VERSION_V2',\n ]),\n /** Command ID for tracking */\n commandId: z.string(),\n /** Ledger offset at which the submission landed — used as `beginExclusive`\n * for waitForCommand to avoid polling from the start of the ledger.\n * Optional: only present after send(); absent for old/retry scenarios. */\n completionOffset: z.number().optional(),\n});\n\n// === Lifecycle schemas ===\n\n/**\n * Canton transaction schema for Daml Ledger API commands.\n *\n * Canton uses an interactive submission (prepare-sign-submit) flow for external party signing.\n * The populatedTransaction contains the commands to send to prepareForSigning.\n */\nexport const cantonTransactionSchema = transactionSchema.extend({\n populatedTransaction: z.object({\n /** Parties submitting the command (actAs) */\n actAs: z.array(z.string()),\n /** Daml commands to send to prepareForSigning */\n commands: z.array(cantonCommandSchema),\n /** Disclosed contracts for contract/key lookups */\n disclosedContracts: z.array(cantonDisclosedContractSchema),\n /** Maps each `actAs` party ID → the senderEntityName that controls its\n * signing key. Optional in the schema, but must be populated and cover\n * every `actAs` party before the transaction can be signed. */\n partyToSenderEntity: z.record(z.string(), z.string()).optional(),\n }),\n});\n\n/**\n * Assigned transaction includes the inflight transaction data.\n */\nexport const cantonAssignedTransactionSchema = assignedTransactionSchema.extend({\n ...cantonTransactionSchema.shape,\n inflightTransaction: cantonInflightTransactionSchema.optional(),\n});\n\n/**\n * Signed transaction includes the DER-encoded ECDSA signature.\n */\nexport const cantonSignedTransactionSchema = signedTransactionSchema.extend({\n ...cantonAssignedTransactionSchema.shape,\n signedTransaction: z.object({\n /** Per-party signatures in the format expected by Canton's submitSigned */\n signatures: z.array(\n z.object({\n party: z.string(),\n signatures: z.array(\n z.object({\n format: z.string(),\n signature: z.string(),\n signedBy: z.string(),\n signingAlgorithmSpec: z.string(),\n }),\n ),\n }),\n ),\n }),\n});\n\n/**\n * Mined transaction with confirmation result.\n */\nexport const cantonMinedTransactionSchema = minedTransactionSchema.extend({\n ...cantonSignedTransactionSchema.shape,\n inflightTransaction: cantonInflightTransactionSchema,\n});\n\n// === Types ===\n\nexport type CantonTx = z.infer<typeof cantonTransactionSchema>;\nexport type CantonAssignedTx = z.infer<typeof cantonAssignedTransactionSchema>;\nexport type CantonSignedTx = z.infer<typeof cantonSignedTransactionSchema>;\nexport type CantonMinedTx = z.infer<typeof cantonMinedTransactionSchema>;\n\n// === Builder ===\n\nexport type BuildCantonTransactionInput = PartialBy<CantonTx, 'chainName' | 'timestamps'>;\n\nexport const buildCantonTransaction = async (\n chainName: string,\n tx: BuildCantonTransactionInput,\n): Promise<CantonTx> => {\n return {\n ...tx,\n chainName,\n timestamps: {\n created: tx.timestamps?.created ?? Date.now(),\n },\n };\n};\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/provider.ts"],"names":["parseCantonUri","uri","url","URL","adminApiHost","searchParams","get","Error","userId","walletUrl","undefined","tokenUrl","clientId","clientSecret","scope","audience","key","delete","jsonApiUrl","toString","replace","oauth2","createCantonProvider","isLocal","params","tokenProvider","createTokenProvider","configuration","Configuration","basePath","accessToken","getToken","client","CantonClient","grpcClient","CantonGrpcClient","host","LocalTokenProvider","actAs","admin","ClientCredentialsTokenProvider"],"mappings":";;;;;;;;AAyDO,SAASA,eAAeC,GAAAA,EAAW;AACtC,EAAA,MAAMC,GAAAA,GAAM,IAAIC,GAAAA,CAAIF,GAAAA,CAAAA;AAIpB,EAAA,MAAMG,YAAAA,GAAeF,GAAAA,CAAIG,YAAAA,CAAaC,GAAAA,CAAI,WAAA,CAAA;AAC1C,EAAA,IAAI,CAACF,YAAAA,EAAc;AACf,IAAA,MAAM,IAAIG,MAAM,kEAAA,CAAA;AACpB,EAAA;AAEA,EAAA,MAAMC,MAAAA,GAASN,GAAAA,CAAIG,YAAAA,CAAaC,GAAAA,CAAI,SAAA,CAAA,IAAc,mBAAA;AAClD,EAAA,MAAMG,SAAAA,GAAYP,GAAAA,CAAIG,YAAAA,CAAaC,GAAAA,CAAI,YAAA,CAAA,IAAiBI,MAAAA;AACxD,EAAA,MAAMC,QAAAA,GAAWT,GAAAA,CAAIG,YAAAA,CAAaC,GAAAA,CAAI,WAAA,CAAA,IAAgBI,MAAAA;AACtD,EAAA,MAAME,QAAAA,GAAWV,GAAAA,CAAIG,YAAAA,CAAaC,GAAAA,CAAI,WAAA,CAAA,IAAgBI,MAAAA;AACtD,EAAA,MAAMG,YAAAA,GAAeX,GAAAA,CAAIG,YAAAA,CAAaC,GAAAA,CAAI,eAAA,CAAA,IAAoBI,MAAAA;AAC9D,EAAA,MAAMI,KAAAA,GAAQZ,GAAAA,CAAIG,YAAAA,CAAaC,GAAAA,CAAI,OAAA,CAAA,IAAYI,MAAAA;AAC/C,EAAA,MAAMK,QAAAA,GAAWb,GAAAA,CAAIG,YAAAA,CAAaC,GAAAA,CAAI,UAAA,CAAA,IAAeI,MAAAA;AAErD,EAAA,KAAA,MAAWM,GAAAA,IAAO;AACd,IAAA,WAAA;AACA,IAAA,SAAA;AACA,IAAA,YAAA;AACA,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,eAAA;AACA,IAAA,OAAA;AACA,IAAA;AACD,GAAA,EAAA;AACCd,IAAAA,GAAAA,CAAIG,YAAAA,CAAaY,OAAOD,GAAAA,CAAAA;AAC5B,EAAA;AAEA,EAAA,MAAME,aAAahB,GAAAA,CAAIiB,QAAAA,EAAQ,CAAGC,OAAAA,CAAQ,OAAO,EAAA,CAAA;AAEjD,EAAA,MAAMC,MAAAA,GACFV,QAAAA,IAAYC,QAAAA,IAAYC,YAAAA,GAClB;AAAEF,IAAAA,QAAAA;AAAUC,IAAAA,QAAAA;AAAUC,IAAAA,YAAAA;AAAcC,IAAAA,KAAAA;AAAOC,IAAAA;GAAS,GACpDL,MAAAA;AAEV,EAAA,OAAO;AAAEQ,IAAAA,UAAAA;AAAYd,IAAAA,YAAAA;AAAcI,IAAAA,MAAAA;AAAQC,IAAAA,SAAAA;AAAWY,IAAAA;AAAO,GAAA;AACjE;AAvCgBrB,MAAAA,CAAAA,cAAAA,EAAAA,gBAAAA,CAAAA;AA2DT,SAASsB,oBAAAA,CAAqB,EACjCrB,GAAAA,EACAsB,OAAAA,EAAO,EACmB;AAC1B,EAAA,MAAMC,MAAAA,GAASxB,eAAeC,GAAAA,CAAAA;AAE9B,EAAA,MAAMwB,aAAAA,GAAgBC,mBAAAA,CAAoBF,MAAAA,EAAQD,OAAAA,CAAAA;AAGlD,EAAA,MAAMI,aAAAA,GAAgB,IAAIC,aAAAA,CAAc;AACpCC,IAAAA,QAAAA,EAAUL,MAAAA,CAAON,UAAAA;IACjBY,WAAAA,kBAAa,MAAA,CAAA,MAAML,aAAAA,CAAcM,QAAAA,EAAQ,EAA5B,aAAA;GACjB,CAAA;AACA,EAAA,MAAMC,MAAAA,GAAS,IAAIC,YAAAA,CAAaN,aAAAA,EAAeH,OAAOhB,MAAM,CAAA;AAG5D,EAAA,MAAM0B,UAAAA,GAAa,IAAIC,gBAAAA,CAAiB;AACpCC,IAAAA,IAAAA,EAAMZ,MAAAA,CAAOpB,YAAAA;AACbqB,IAAAA;GACJ,CAAA;AAEA,EAAA,OAAO;AACHO,IAAAA,MAAAA;AACAE,IAAAA,UAAAA;AACAT,IAAAA,aAAAA;AACAhB,IAAAA,SAAAA,EAAWe,MAAAA,CAAOf;AACtB,GAAA;AACJ;AA3BgBa,MAAAA,CAAAA,oBAAAA,EAAAA,sBAAAA,CAAAA;AA6BhB,SAASI,mBAAAA,CAAoBF,QAAyBD,OAAAA,EAAgB;AAClE,EAAA,IAAIA,OAAAA,EAAS;AACT,IAAA,OAAO,IAAIc,kBAAAA,CAAmB;AAC1B7B,MAAAA,MAAAA,EAAQgB,MAAAA,CAAOhB,MAAAA;AACf8B,MAAAA,KAAAA,EAAO,EAAA;MACPC,KAAAA,EAAO;KACX,CAAA;AACJ,EAAA;AAGA,EAAA,IAAI,CAACf,OAAOH,MAAAA,EAAQ;AAChB,IAAA,MAAM,IAAId,MACN,uGAAA,CAAA;AAER,EAAA;AAEA,EAAA,OAAO,IAAIiC,8BAAAA,CAA+BhB,MAAAA,CAAOH,MAAM,CAAA;AAC3D;AAjBSK,MAAAA,CAAAA,mBAAAA,EAAAA,qBAAAA,CAAAA","file":"WQTILDML.js","sourcesContent":["import {\n ClientCredentialsTokenProvider,\n type ClientCredentialsTokenProviderConfig,\n} from './auth/client-credentials-token-provider';\nimport { LocalTokenProvider } from './auth/local-token-provider';\nimport type { TokenProvider } from './auth/token-provider';\nimport { CantonClient } from './client/canton-client';\nimport { CantonGrpcClient } from './client/grpc';\nimport type { ICantonClient } from './client/interface';\nimport { Configuration } from './open-api/runtime';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Provider Type\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Composite provider for Canton — bundles both transport layers and shared auth.\n *\n * - {@link client} — JSON Ledger API (commands, queries, updates)\n * - {@link grpcClient} — gRPC Admin API (topology transactions, namespace queries)\n * - {@link tokenProvider} — Shared Bearer-token source used by both transports\n */\nexport type CantonProvider = {\n client: ICantonClient;\n grpcClient: CantonGrpcClient;\n tokenProvider: TokenProvider;\n /** Validator wallet URL for scan-proxy CIP-56 endpoints. */\n walletUrl?: string;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// URI Parsing\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type CantonUriParams = {\n /** Base URL of the JSON Ledger API (e.g. \"http://localhost:5975\") */\n jsonApiUrl: string;\n /** Host:port of the gRPC Admin API (e.g. \"localhost:5076\") */\n adminApiHost: string;\n /** Ledger API user ID (default: \"participant_admin\") */\n userId: string;\n /** Validator wallet URL for scan-proxy CIP-56 endpoints (e.g. \"http://localhost:7201\") */\n walletUrl?: string;\n /** OAuth2 client credentials config — present only for non-local environments */\n oauth2?: ClientCredentialsTokenProviderConfig;\n};\n\n/**\n * Parse a Canton provider URI into its constituent parts.\n *\n * URI format:\n * `<json-api-base>?admin-api=<host:port>&user-id=<id>[&token-url=...&client-id=...&client-secret=...&scope=...&audience=...]`\n *\n * The base URL (everything before the query string) is the JSON Ledger API endpoint.\n * Canton-specific params are extracted and removed; any remaining query params are\n * preserved on the JSON API URL.\n */\nexport function parseCantonUri(uri: string): CantonUriParams {\n const url = new URL(uri);\n\n // `admin-api` is a gRPC `host:port` (no scheme), so it carries no TLS signal.\n // TODO(CANTON): convey TLS for non-localhost (e.g. `&admin-api-tls=1` or `admin-api=grpcs://host:port`).\n const adminApiHost = url.searchParams.get('admin-api');\n if (!adminApiHost) {\n throw new Error('Canton provider URI missing required \"admin-api\" query parameter');\n }\n\n const userId = url.searchParams.get('user-id') ?? 'participant_admin';\n const walletUrl = url.searchParams.get('wallet-url') ?? undefined;\n const tokenUrl = url.searchParams.get('token-url') ?? undefined;\n const clientId = url.searchParams.get('client-id') ?? undefined;\n const clientSecret = url.searchParams.get('client-secret') ?? undefined;\n const scope = url.searchParams.get('scope') ?? undefined;\n const audience = url.searchParams.get('audience') ?? undefined;\n\n for (const key of [\n 'admin-api',\n 'user-id',\n 'wallet-url',\n 'token-url',\n 'client-id',\n 'client-secret',\n 'scope',\n 'audience',\n ]) {\n url.searchParams.delete(key);\n }\n\n const jsonApiUrl = url.toString().replace(/\\/$/, '');\n\n const oauth2 =\n tokenUrl && clientId && clientSecret\n ? { tokenUrl, clientId, clientSecret, scope, audience }\n : undefined;\n\n return { jsonApiUrl, adminApiHost, userId, walletUrl, oauth2 };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Provider Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type CreateCantonProviderOptions = {\n /** Raw provider URI (from provider config) */\n uri: string;\n /** When true, uses LocalTokenProvider (self-signed JWTs) instead of OAuth2 */\n isLocal: boolean;\n};\n\n/**\n * Create a {@link CantonProvider} from a provider URI.\n *\n * - **isLocal=true**: Uses {@link LocalTokenProvider} with admin-level access (self-signed JWTs).\n * - **isLocal=false**: Uses {@link ClientCredentialsTokenProvider} with OAuth2 client\n * credentials extracted from the URI query parameters.\n */\nexport function createCantonProvider({\n uri,\n isLocal,\n}: CreateCantonProviderOptions): CantonProvider {\n const params = parseCantonUri(uri);\n\n const tokenProvider = createTokenProvider(params, isLocal);\n\n // ── JSON Ledger API Client ──────────────────────────────────────────\n const configuration = new Configuration({\n basePath: params.jsonApiUrl,\n accessToken: () => tokenProvider.getToken(),\n });\n const client = new CantonClient(configuration, params.userId);\n\n // ── gRPC Admin API Client ───────────────────────────────────────────\n const grpcClient = new CantonGrpcClient({\n host: params.adminApiHost,\n tokenProvider,\n });\n\n return {\n client,\n grpcClient,\n tokenProvider,\n walletUrl: params.walletUrl,\n };\n}\n\nfunction createTokenProvider(params: CantonUriParams, isLocal: boolean): TokenProvider {\n if (isLocal) {\n return new LocalTokenProvider({\n userId: params.userId,\n actAs: [],\n admin: true,\n });\n }\n\n // TODO(CANTON): add other prod auth methods (direct JWT passthrough, etc.).\n if (!params.oauth2) {\n throw new Error(\n 'Canton provider requires OAuth2 credentials (token-url, client-id, client-secret) in the provider URI',\n );\n }\n\n return new ClientCredentialsTokenProvider(params.oauth2);\n}\n"]}