@layerzerolabs/common-canton 0.2.102 → 0.2.104
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/.turbo/turbo-build.log +718 -710
- package/.turbo/turbo-test.log +18 -18
- package/dist/{KNUJUERI.js → 25GNLJIH.js} +3 -3
- package/dist/{KNUJUERI.js.map → 25GNLJIH.js.map} +1 -1
- package/dist/{SIXVG7DR.js → 2UWZKS5E.js} +3 -3
- package/dist/{SIXVG7DR.js.map → 2UWZKS5E.js.map} +1 -1
- package/dist/{JGMLJJM5.js → 37DZS34C.js} +3 -3
- package/dist/{JGMLJJM5.js.map → 37DZS34C.js.map} +1 -1
- package/dist/{ORO3GF7S.js → 3UD2GTXW.js} +3 -3
- package/dist/{ORO3GF7S.js.map → 3UD2GTXW.js.map} +1 -1
- package/dist/{CJEDJ6BA.js → 3YCNHEVD.js} +40 -9
- package/dist/3YCNHEVD.js.map +1 -0
- package/dist/{XUUV67AB.js → 42XERBT4.js} +3 -3
- package/dist/{XUUV67AB.js.map → 42XERBT4.js.map} +1 -1
- package/dist/{WCCLV452.js → 4AKFOZFY.js} +5 -5
- package/dist/{WCCLV452.js.map → 4AKFOZFY.js.map} +1 -1
- package/dist/{QHLG5QK7.js → 4AM6UVPL.js} +3 -3
- package/dist/{QHLG5QK7.js.map → 4AM6UVPL.js.map} +1 -1
- package/dist/{ZPTSW4ST.js → 4UM5TVKI.js} +3 -3
- package/dist/{ZPTSW4ST.js.map → 4UM5TVKI.js.map} +1 -1
- package/dist/{B7EQ3SWK.js → 4VLNRPYZ.js} +3 -3
- package/dist/{B7EQ3SWK.js.map → 4VLNRPYZ.js.map} +1 -1
- package/dist/{G4PPJP65.js → 5N747JZQ.js} +3 -3
- package/dist/{G4PPJP65.js.map → 5N747JZQ.js.map} +1 -1
- package/dist/{PI2K7A3Q.js → 5RZS7DZN.js} +3 -3
- package/dist/{PI2K7A3Q.js.map → 5RZS7DZN.js.map} +1 -1
- package/dist/{T5NCFR3W.js → 623CCK2L.js} +3 -3
- package/dist/{T5NCFR3W.js.map → 623CCK2L.js.map} +1 -1
- package/dist/{C77Y3MIG.js → 6GAFSKMN.js} +3 -3
- package/dist/{C77Y3MIG.js.map → 6GAFSKMN.js.map} +1 -1
- package/dist/{SWAXT3ZN.js → A7U4VVQK.js} +3 -3
- package/dist/{SWAXT3ZN.js.map → A7U4VVQK.js.map} +1 -1
- package/dist/{3GTU7DXV.js → AV2FN74T.js} +4 -4
- package/dist/{3GTU7DXV.js.map → AV2FN74T.js.map} +1 -1
- package/dist/{OZ5IUCBI.js → AYAFFPBV.js} +3 -3
- package/dist/{OZ5IUCBI.js.map → AYAFFPBV.js.map} +1 -1
- package/dist/{3EHEF6PF.js → BJXKGZ5Y.js} +4 -4
- package/dist/{3EHEF6PF.js.map → BJXKGZ5Y.js.map} +1 -1
- package/dist/{JEGCDOON.js → CLFKYN43.js} +4 -4
- package/dist/{JEGCDOON.js.map → CLFKYN43.js.map} +1 -1
- package/dist/{K4SNVOCJ.js → CXFHE5WB.js} +3 -3
- package/dist/{K4SNVOCJ.js.map → CXFHE5WB.js.map} +1 -1
- package/dist/{75QKYROD.js → CXNQT7WY.js} +2 -2
- package/dist/{75QKYROD.js.map → CXNQT7WY.js.map} +1 -1
- package/dist/{F46SX6MN.js → D3AV6J7R.js} +3 -3
- package/dist/{F46SX6MN.js.map → D3AV6J7R.js.map} +1 -1
- package/dist/{46Y2JCNE.js → EIXIZULE.js} +35 -35
- package/dist/{46Y2JCNE.js.map → EIXIZULE.js.map} +1 -1
- package/dist/{ZY3FX7W5.js → GMQEAD3I.js} +3 -3
- package/dist/{ZY3FX7W5.js.map → GMQEAD3I.js.map} +1 -1
- package/dist/{KBZ6YXX4.js → H7FW24YI.js} +3 -3
- package/dist/{KBZ6YXX4.js.map → H7FW24YI.js.map} +1 -1
- package/dist/{QSYGA6OS.js → ICTUC6FF.js} +3 -3
- package/dist/{QSYGA6OS.js.map → ICTUC6FF.js.map} +1 -1
- package/dist/{Y4LSYZDO.js → IOTRKLGP.js} +4 -4
- package/dist/{Y4LSYZDO.js.map → IOTRKLGP.js.map} +1 -1
- package/dist/{MVXDS4XR.js → JKQLMXRN.js} +3 -3
- package/dist/{MVXDS4XR.js.map → JKQLMXRN.js.map} +1 -1
- package/dist/{WDSUM647.js → JRFMLEIC.js} +3 -3
- package/dist/{WDSUM647.js.map → JRFMLEIC.js.map} +1 -1
- package/dist/{JTRUQM7V.js → JV2DWUBW.js} +74 -12
- package/dist/JV2DWUBW.js.map +1 -0
- package/dist/{YCJNLHFD.js → KCRFOKIB.js} +3 -3
- package/dist/{YCJNLHFD.js.map → KCRFOKIB.js.map} +1 -1
- package/dist/{TGWOYSYK.js → KJRFPBY4.js} +3 -3
- package/dist/{TGWOYSYK.js.map → KJRFPBY4.js.map} +1 -1
- package/dist/{4GYCD3G4.js → KK2NBQSG.js} +3 -3
- package/dist/{4GYCD3G4.js.map → KK2NBQSG.js.map} +1 -1
- package/dist/{3KJAGL4R.js → MDEOBKC3.js} +3 -3
- package/dist/{3KJAGL4R.js.map → MDEOBKC3.js.map} +1 -1
- package/dist/{CTDZ456O.js → MDLCDBAQ.js} +13 -7
- package/dist/MDLCDBAQ.js.map +1 -0
- package/dist/{ZOR226BV.js → MJCI4XZ2.js} +3 -3
- package/dist/{ZOR226BV.js.map → MJCI4XZ2.js.map} +1 -1
- package/dist/{YKFGZTXG.js → MZMRFQTR.js} +3 -3
- package/dist/{YKFGZTXG.js.map → MZMRFQTR.js.map} +1 -1
- package/dist/{JO5BWI3K.js → NLMU226B.js} +3 -3
- package/dist/{JO5BWI3K.js.map → NLMU226B.js.map} +1 -1
- package/dist/{TBC7IPN4.js → NWXHRFA3.js} +4 -4
- package/dist/{TBC7IPN4.js.map → NWXHRFA3.js.map} +1 -1
- package/dist/{WVIUQYTV.js → NX67V54F.js} +3 -3
- package/dist/{WVIUQYTV.js.map → NX67V54F.js.map} +1 -1
- package/dist/{A2K22XWL.js → OMRF3GH2.js} +3 -3
- package/dist/{A2K22XWL.js.map → OMRF3GH2.js.map} +1 -1
- package/dist/{U4Y3HOBO.js → OQ2FVATH.js} +3 -3
- package/dist/{U4Y3HOBO.js.map → OQ2FVATH.js.map} +1 -1
- package/dist/{OQKVGBIX.js → P3A2XIFY.js} +3 -3
- package/dist/{OQKVGBIX.js.map → P3A2XIFY.js.map} +1 -1
- package/dist/{KDGN5Z34.js → PHVMGN7T.js} +3 -3
- package/dist/{KDGN5Z34.js.map → PHVMGN7T.js.map} +1 -1
- package/dist/{NZJBYDXC.js → PVONQCBG.js} +3 -3
- package/dist/{NZJBYDXC.js.map → PVONQCBG.js.map} +1 -1
- package/dist/{73I7CBP3.js → QYQCAXCB.js} +3 -3
- package/dist/{73I7CBP3.js.map → QYQCAXCB.js.map} +1 -1
- package/dist/{ONXLINKX.js → R26MH4UH.js} +4 -4
- package/dist/{ONXLINKX.js.map → R26MH4UH.js.map} +1 -1
- package/dist/{35Q7BMW7.js → REC34FNU.js} +3 -3
- package/dist/{35Q7BMW7.js.map → REC34FNU.js.map} +1 -1
- package/dist/{HCFMCRFF.js → RQXQCK22.js} +3 -3
- package/dist/{HCFMCRFF.js.map → RQXQCK22.js.map} +1 -1
- package/dist/{VVBAHHOY.js → TL2NURGK.js} +4 -4
- package/dist/{VVBAHHOY.js.map → TL2NURGK.js.map} +1 -1
- package/dist/{AMLJTQWB.js → TWUSN2QY.js} +3 -3
- package/dist/{AMLJTQWB.js.map → TWUSN2QY.js.map} +1 -1
- package/dist/{NKXEPWZV.js → U7ISOK6B.js} +3 -3
- package/dist/{NKXEPWZV.js.map → U7ISOK6B.js.map} +1 -1
- package/dist/{6YYHHOJO.js → VVR6BIVE.js} +3 -3
- package/dist/{6YYHHOJO.js.map → VVR6BIVE.js.map} +1 -1
- package/dist/{5SIPGHZY.js → W53LLP7R.js} +3 -3
- package/dist/{5SIPGHZY.js.map → W53LLP7R.js.map} +1 -1
- package/dist/{ZLPED4Y2.js → WIQFSNER.js} +3 -3
- package/dist/{ZLPED4Y2.js.map → WIQFSNER.js.map} +1 -1
- package/dist/{STHJGYPG.js → WRPKZZ4E.js} +3 -3
- package/dist/{STHJGYPG.js.map → WRPKZZ4E.js.map} +1 -1
- package/dist/{Y53QRDCG.js → XSEEW6TB.js} +3 -3
- package/dist/{Y53QRDCG.js.map → XSEEW6TB.js.map} +1 -1
- package/dist/{DCGM3XRM.js → YAMAXOF4.js} +3 -3
- package/dist/{DCGM3XRM.js.map → YAMAXOF4.js.map} +1 -1
- package/dist/{OELP4BR2.js → YN7J2UOM.js} +3 -3
- package/dist/{OELP4BR2.js.map → YN7J2UOM.js.map} +1 -1
- package/dist/YVZO3C4U.js +41 -0
- package/dist/YVZO3C4U.js.map +1 -0
- package/dist/{KH7RP6Q4.js → ZF6ASBPX.js} +3 -3
- package/dist/{KH7RP6Q4.js.map → ZF6ASBPX.js.map} +1 -1
- package/dist/{EDQ6FYO4.js → ZN2CNFMH.js} +3 -3
- package/dist/{EDQ6FYO4.js.map → ZN2CNFMH.js.map} +1 -1
- package/dist/client/canton-client.d.ts +29 -1
- package/dist/client/canton-client.d.ts.map +1 -1
- package/dist/client/canton-client.js +90 -90
- package/dist/client/index.js +91 -91
- package/dist/client/interface.d.ts +15 -1
- package/dist/client/interface.d.ts.map +1 -1
- package/dist/events.js +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +99 -98
- package/dist/open-api/apis/DefaultApi.js +89 -89
- package/dist/open-api/apis/index.js +89 -89
- package/dist/open-api/index.js +89 -89
- package/dist/open-api/models/Command1.js +2 -2
- package/dist/open-api/models/Completion.js +1 -1
- package/dist/open-api/models/Completion1.js +1 -1
- package/dist/open-api/models/CompletionResponse.js +1 -1
- package/dist/open-api/models/CompletionResponseOneOf.js +1 -1
- package/dist/open-api/models/CompletionStreamResponse.js +1 -1
- package/dist/open-api/models/CreateUserRequest.js +5 -5
- package/dist/open-api/models/CumulativeFilter.js +3 -3
- package/dist/open-api/models/DeduplicationPeriod1.js +1 -1
- package/dist/open-api/models/DeduplicationPeriod2.js +2 -2
- package/dist/open-api/models/Event.js +2 -2
- package/dist/open-api/models/EventFormat.js +5 -5
- package/dist/open-api/models/ExperimentalFeatures.js +2 -2
- package/dist/open-api/models/FeaturesDescriptor.js +3 -3
- package/dist/open-api/models/Filters.js +4 -4
- package/dist/open-api/models/GetActiveContractsRequest.js +7 -7
- package/dist/open-api/models/GetEventsByContractIdRequest.js +6 -6
- package/dist/open-api/models/GetLedgerApiVersionResponse.js +4 -4
- package/dist/open-api/models/GetTransactionByIdRequest.js +7 -7
- package/dist/open-api/models/GetTransactionByOffsetRequest.js +7 -7
- package/dist/open-api/models/GetUpdateByIdRequest.js +8 -8
- package/dist/open-api/models/GetUpdateByOffsetRequest.js +8 -8
- package/dist/open-api/models/GetUpdatesRequest.js +9 -9
- package/dist/open-api/models/GrantUserRightsRequest.js +4 -4
- package/dist/open-api/models/GrantUserRightsResponse.js +4 -4
- package/dist/open-api/models/IdentifierFilter.js +2 -2
- package/dist/open-api/models/JsContractEntry.js +2 -2
- package/dist/open-api/models/JsExecuteSubmissionAndWaitForTransactionRequest.js +12 -12
- package/dist/open-api/models/JsExecuteSubmissionAndWaitForTransactionResponse.js +4 -4
- package/dist/open-api/models/JsExecuteSubmissionAndWaitRequest.js +6 -6
- package/dist/open-api/models/JsExecuteSubmissionRequest.js +6 -6
- package/dist/open-api/models/JsGetActiveContractsResponse.js +3 -3
- package/dist/open-api/models/JsGetTransactionResponse.js +4 -4
- package/dist/open-api/models/JsGetUpdateResponse.js +15 -15
- package/dist/open-api/models/JsGetUpdatesResponse.js +15 -15
- package/dist/open-api/models/JsPrepareSubmissionRequest.js +4 -4
- package/dist/open-api/models/JsSubmitAndWaitForTransactionRequest.js +11 -11
- package/dist/open-api/models/JsSubmitAndWaitForTransactionResponse.js +4 -4
- package/dist/open-api/models/JsTopologyTransaction.js +6 -6
- package/dist/open-api/models/JsTransaction.js +3 -3
- package/dist/open-api/models/Kind.js +2 -2
- package/dist/open-api/models/ListUserRightsResponse.js +4 -4
- package/dist/open-api/models/MinLedgerTime.js +3 -3
- package/dist/open-api/models/ReassignmentCommand.js +3 -3
- package/dist/open-api/models/ReassignmentCommands.js +4 -4
- package/dist/open-api/models/RevokeUserRightsRequest.js +4 -4
- package/dist/open-api/models/RevokeUserRightsResponse.js +4 -4
- package/dist/open-api/models/Right.js +3 -3
- package/dist/open-api/models/SubmitAndWaitForReassignmentRequest.js +10 -10
- package/dist/open-api/models/SubmitReassignmentRequest.js +5 -5
- package/dist/open-api/models/Time.js +2 -2
- package/dist/open-api/models/TopologyEvent.js +5 -5
- package/dist/open-api/models/TopologyEventEvent.js +4 -4
- package/dist/open-api/models/TopologyTransaction.js +7 -7
- package/dist/open-api/models/Transaction.js +4 -4
- package/dist/open-api/models/TransactionFilter.js +5 -5
- package/dist/open-api/models/TransactionFormat.js +6 -6
- package/dist/open-api/models/Update.js +14 -14
- package/dist/open-api/models/UpdateFormat.js +7 -7
- package/dist/open-api/models/UpdateOneOf2.js +8 -8
- package/dist/open-api/models/UpdateOneOf3.js +5 -5
- package/dist/open-api/models/UpdatePartyDetailsRequest.js +1 -1
- package/dist/open-api/models/UpdateUserRequest.js +1 -1
- package/dist/open-api/models/index.js +88 -88
- package/dist/provider.d.ts +5 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +93 -93
- package/dist/senderPlaceholder.d.ts +41 -0
- package/dist/senderPlaceholder.d.ts.map +1 -0
- package/dist/senderPlaceholder.js +4 -0
- package/dist/senderPlaceholder.js.map +1 -0
- package/dist/transaction.d.ts +77 -11
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +1 -1
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/eslint.config.js +3 -1
- package/package.json +9 -9
- package/src/client/canton-client.ts +72 -6
- package/src/client/interface.ts +17 -0
- package/src/index.ts +3 -0
- package/src/provider.ts +24 -8
- package/src/senderPlaceholder.ts +119 -0
- package/src/transaction.ts +54 -8
- package/src/types.ts +33 -0
- package/dist/CJEDJ6BA.js.map +0 -1
- package/dist/CTDZ456O.js.map +0 -1
- package/dist/JTRUQM7V.js.map +0 -1
package/dist/types.js
CHANGED
package/eslint.config.js
CHANGED
|
@@ -5,6 +5,8 @@ export default [
|
|
|
5
5
|
...baseConfig,
|
|
6
6
|
{
|
|
7
7
|
// TODO Cover source code in `scripts` and `tests` directories.
|
|
8
|
-
|
|
8
|
+
// src/open-api is generated by openapi-generator at build time (gitignored); its emitted
|
|
9
|
+
// eslint-disable directives trip --max-warnings 0, so exclude it from linting.
|
|
10
|
+
ignores: ['dist', 'node_modules', 'scripts', 'test', 'src/open-api'],
|
|
9
11
|
},
|
|
10
12
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layerzerolabs/common-canton",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.104",
|
|
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.
|
|
25
|
-
"@layerzerolabs/typescript-utils": "0.2.
|
|
24
|
+
"@layerzerolabs/common-chain-model": "0.2.104",
|
|
25
|
+
"@layerzerolabs/typescript-utils": "0.2.104"
|
|
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/
|
|
35
|
-
"@layerzerolabs/tsup-configuration": "0.2.
|
|
36
|
-
"@layerzerolabs/
|
|
37
|
-
"@layerzerolabs/ver-signer-adapter": "0.2.
|
|
38
|
-
"@layerzerolabs/
|
|
39
|
-
"@layerzerolabs/
|
|
34
|
+
"@layerzerolabs/eslint-configuration": "^0.2.104",
|
|
35
|
+
"@layerzerolabs/tsup-configuration": "0.2.104",
|
|
36
|
+
"@layerzerolabs/typescript-configuration": "0.2.104",
|
|
37
|
+
"@layerzerolabs/ver-signer-adapter": "0.2.104",
|
|
38
|
+
"@layerzerolabs/vitest-configuration": "0.2.104",
|
|
39
|
+
"@layerzerolabs/vm-tooling-canton": "0.2.104"
|
|
40
40
|
},
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "restricted",
|
|
@@ -29,6 +29,7 @@ import type {
|
|
|
29
29
|
PreparedTransaction,
|
|
30
30
|
SubmitActors,
|
|
31
31
|
SubmitResult,
|
|
32
|
+
UserRight,
|
|
32
33
|
WaitOptions,
|
|
33
34
|
WaitResult,
|
|
34
35
|
} from '../types';
|
|
@@ -304,6 +305,49 @@ export class CantonClient implements ICantonClient {
|
|
|
304
305
|
};
|
|
305
306
|
}
|
|
306
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Return the rights granted to the current user (this.#userId).
|
|
310
|
+
*
|
|
311
|
+
* Bypasses the OpenAPI generator's typed `Kind` converter, which is
|
|
312
|
+
* broken: `instanceOfKindOneOf` checks lowercase `canActAs in value`, but
|
|
313
|
+
* `KindOneOfFromJSONTyped` reads uppercase `json['CanActAs']`, so the
|
|
314
|
+
* typed client returns every `kind` as `{}`. We parse the raw JSON
|
|
315
|
+
* ourselves to preserve the actual variant payload.
|
|
316
|
+
*/
|
|
317
|
+
async listUserRights(): Promise<UserRight[]> {
|
|
318
|
+
const apiResponse = await this.#api.getV2UsersUserIdRightsRaw({
|
|
319
|
+
userId: this.#userId,
|
|
320
|
+
});
|
|
321
|
+
const raw = (await apiResponse.raw.json()) as { rights?: UserRight[] };
|
|
322
|
+
return raw.rights ?? [];
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Return the parties the current user has CanActAs or CanReadAs rights
|
|
327
|
+
* for. Convenience wrapper over `listUserRights()` for the common case
|
|
328
|
+
* where the caller just needs party-scoped access (e.g. to query events
|
|
329
|
+
* or fetch transactions).
|
|
330
|
+
*
|
|
331
|
+
* Use this instead of `listParties()` when the caller only has scoped
|
|
332
|
+
* rights — `listParties()` returns *all* parties on the participant
|
|
333
|
+
* (including DSO, splice parties), and Canton returns 403 if you query
|
|
334
|
+
* as a party you can't read.
|
|
335
|
+
*/
|
|
336
|
+
async listUserParties(): Promise<string[]> {
|
|
337
|
+
const rights = await this.listUserRights();
|
|
338
|
+
const parties = new Set<string>();
|
|
339
|
+
for (const right of rights) {
|
|
340
|
+
// Only `CanActAs` / `CanReadAs` carry a party; the other four
|
|
341
|
+
// variants (ParticipantAdmin, IdentityProviderAdmin,
|
|
342
|
+
// CanReadAsAnyParty, CanExecuteAsAnyParty) have empty payloads.
|
|
343
|
+
const party = right.kind.CanActAs?.value.party ?? right.kind.CanReadAs?.value.party;
|
|
344
|
+
if (party !== undefined) {
|
|
345
|
+
parties.add(party);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return [...parties];
|
|
349
|
+
}
|
|
350
|
+
|
|
307
351
|
/**
|
|
308
352
|
* Allocate a new party on the participant node.
|
|
309
353
|
*
|
|
@@ -736,7 +780,12 @@ export class CantonClient implements ICantonClient {
|
|
|
736
780
|
},
|
|
737
781
|
};
|
|
738
782
|
|
|
739
|
-
|
|
783
|
+
let response;
|
|
784
|
+
try {
|
|
785
|
+
response = await this.#api.postV2InteractiveSubmissionPrepare(request);
|
|
786
|
+
} catch (error: unknown) {
|
|
787
|
+
throw await this.#throwApiError(error, 'Interactive submission prepare');
|
|
788
|
+
}
|
|
740
789
|
const validated = this.#validatePrepareResponse(response);
|
|
741
790
|
|
|
742
791
|
return {
|
|
@@ -788,7 +837,11 @@ export class CantonClient implements ICantonClient {
|
|
|
788
837
|
},
|
|
789
838
|
};
|
|
790
839
|
|
|
791
|
-
|
|
840
|
+
try {
|
|
841
|
+
await this.#api.postV2InteractiveSubmissionExecute(request);
|
|
842
|
+
} catch (error: unknown) {
|
|
843
|
+
throw await this.#throwApiError(error, 'Interactive submission execute');
|
|
844
|
+
}
|
|
792
845
|
|
|
793
846
|
return { commandId: prepared.commandId, completionOffset };
|
|
794
847
|
}
|
|
@@ -868,6 +921,12 @@ export class CantonClient implements ICantonClient {
|
|
|
868
921
|
/**
|
|
869
922
|
* Stream transactions from a given offset.
|
|
870
923
|
*
|
|
924
|
+
* Uses `updateFormat` with `TRANSACTION_SHAPE_LEDGER_EFFECTS` so consumers
|
|
925
|
+
* receive `ExercisedEvent`s (e.g. the request-poller depends on
|
|
926
|
+
* `Request_Create` exercise results). The deprecated legacy `filter`
|
|
927
|
+
* shape would default to `ACS_DELTA`, which only emits Created/Archived
|
|
928
|
+
* events and silently drops every exercise on the wire.
|
|
929
|
+
*
|
|
871
930
|
* @param party - Party to query as
|
|
872
931
|
* @param beginExclusive - Start offset (exclusive)
|
|
873
932
|
* @param endInclusive - End offset (inclusive)
|
|
@@ -880,16 +939,23 @@ export class CantonClient implements ICantonClient {
|
|
|
880
939
|
endInclusive: number,
|
|
881
940
|
opts?: { templateIds?: string[]; limit?: number },
|
|
882
941
|
): Promise<CantonUpdate[]> {
|
|
942
|
+
const eventFormat = {
|
|
943
|
+
filtersByParty: {
|
|
944
|
+
[party]: { cumulative: this.#buildCumulativeFilters(opts?.templateIds) },
|
|
945
|
+
},
|
|
946
|
+
verbose: false,
|
|
947
|
+
};
|
|
883
948
|
const rawResponse = await this.#api.postV2UpdatesRaw({
|
|
884
949
|
getUpdatesRequest: {
|
|
885
950
|
beginExclusive,
|
|
886
951
|
endInclusive,
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
952
|
+
verbose: false,
|
|
953
|
+
updateFormat: {
|
|
954
|
+
includeTransactions: {
|
|
955
|
+
eventFormat,
|
|
956
|
+
transactionShape: 'TRANSACTION_SHAPE_LEDGER_EFFECTS' as const,
|
|
890
957
|
},
|
|
891
958
|
},
|
|
892
|
-
verbose: true,
|
|
893
959
|
},
|
|
894
960
|
limit: opts?.limit,
|
|
895
961
|
});
|
package/src/client/interface.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
PreparedTransaction,
|
|
18
18
|
SubmitActors,
|
|
19
19
|
SubmitResult,
|
|
20
|
+
UserRight,
|
|
20
21
|
WaitOptions,
|
|
21
22
|
WaitResult,
|
|
22
23
|
} from '../types';
|
|
@@ -178,6 +179,22 @@ export interface ICantonClient {
|
|
|
178
179
|
pageToken?: string;
|
|
179
180
|
}): Promise<{ parties: string[]; nextPageToken: string }>;
|
|
180
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Return the rights granted to the current user (this user's userId in
|
|
184
|
+
* the underlying token).
|
|
185
|
+
*
|
|
186
|
+
* GET /v2/users/{userId}/rights
|
|
187
|
+
*/
|
|
188
|
+
listUserRights(): Promise<UserRight[]>;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Convenience wrapper over `listUserRights()` returning just the parties
|
|
192
|
+
* the current user has CanActAs / CanReadAs rights for. Use instead of
|
|
193
|
+
* `listParties()` when the call requires scoped read access (Canton
|
|
194
|
+
* returns 403 if you query as a party you can't read).
|
|
195
|
+
*/
|
|
196
|
+
listUserParties(): Promise<string[]>;
|
|
197
|
+
|
|
181
198
|
/**
|
|
182
199
|
* Allocate a new party on the participant node.
|
|
183
200
|
*
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './auth';
|
|
2
2
|
export * from './events';
|
|
3
3
|
export * from './provider';
|
|
4
|
+
export * from './senderPlaceholder';
|
|
4
5
|
export * from './transaction';
|
|
5
6
|
|
|
6
7
|
// Core types
|
|
@@ -13,6 +14,8 @@ export {
|
|
|
13
14
|
type SubmitActors,
|
|
14
15
|
type SubmitResult,
|
|
15
16
|
type TemplateId,
|
|
17
|
+
type UserRight,
|
|
18
|
+
type UserRightKind,
|
|
16
19
|
type WaitOptions,
|
|
17
20
|
type WaitResult,
|
|
18
21
|
} from './types';
|
package/src/provider.ts
CHANGED
|
@@ -24,6 +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. Required — amulet fee
|
|
28
|
+
* payment needs it on every Canton transaction; enforced in {@link parseCantonUri}. */
|
|
29
|
+
walletUrl: string;
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -37,6 +40,8 @@ export type CantonUriParams = {
|
|
|
37
40
|
adminApiHost: string;
|
|
38
41
|
/** Ledger API user ID (default: "participant_admin") */
|
|
39
42
|
userId: string;
|
|
43
|
+
/** Validator wallet URL for scan-proxy CIP-56 endpoints (e.g. "http://localhost:7201") */
|
|
44
|
+
walletUrl: string;
|
|
40
45
|
/** OAuth2 client credentials config — present only for non-local environments */
|
|
41
46
|
oauth2?: ClientCredentialsTokenProviderConfig;
|
|
42
47
|
};
|
|
@@ -54,25 +59,33 @@ export type CantonUriParams = {
|
|
|
54
59
|
export function parseCantonUri(uri: string): CantonUriParams {
|
|
55
60
|
const url = new URL(uri);
|
|
56
61
|
|
|
57
|
-
//
|
|
62
|
+
// `admin-api` is a gRPC `host:port` (no scheme), so it carries no TLS signal.
|
|
63
|
+
// TODO(CANTON): convey TLS for non-localhost (e.g. `&admin-api-tls=1` or `admin-api=grpcs://host:port`).
|
|
58
64
|
const adminApiHost = url.searchParams.get('admin-api');
|
|
59
65
|
if (!adminApiHost) {
|
|
60
66
|
throw new Error('Canton provider URI missing required "admin-api" query parameter');
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
const userId = url.searchParams.get('user-id') ?? 'participant_admin';
|
|
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
|
+
}
|
|
64
78
|
const tokenUrl = url.searchParams.get('token-url') ?? undefined;
|
|
65
79
|
const clientId = url.searchParams.get('client-id') ?? undefined;
|
|
66
80
|
const clientSecret = url.searchParams.get('client-secret') ?? undefined;
|
|
67
81
|
const scope = url.searchParams.get('scope') ?? undefined;
|
|
68
82
|
const audience = url.searchParams.get('audience') ?? undefined;
|
|
69
83
|
|
|
70
|
-
// Remove Canton params to get clean JSON API URL
|
|
71
84
|
for (const key of [
|
|
72
85
|
'admin-api',
|
|
73
86
|
'user-id',
|
|
87
|
+
'wallet-url',
|
|
74
88
|
'token-url',
|
|
75
|
-
// TODO: check if these are acceptable in our providers config, we do the same with api-keys currently.
|
|
76
89
|
'client-id',
|
|
77
90
|
'client-secret',
|
|
78
91
|
'scope',
|
|
@@ -81,7 +94,6 @@ export function parseCantonUri(uri: string): CantonUriParams {
|
|
|
81
94
|
url.searchParams.delete(key);
|
|
82
95
|
}
|
|
83
96
|
|
|
84
|
-
// Reconstruct clean base URL (origin + pathname, plus any remaining query params)
|
|
85
97
|
const jsonApiUrl = url.toString().replace(/\/$/, '');
|
|
86
98
|
|
|
87
99
|
const oauth2 =
|
|
@@ -89,7 +101,7 @@ export function parseCantonUri(uri: string): CantonUriParams {
|
|
|
89
101
|
? { tokenUrl, clientId, clientSecret, scope, audience }
|
|
90
102
|
: undefined;
|
|
91
103
|
|
|
92
|
-
return { jsonApiUrl, adminApiHost, userId, oauth2 };
|
|
104
|
+
return { jsonApiUrl, adminApiHost, userId, walletUrl, oauth2 };
|
|
93
105
|
}
|
|
94
106
|
|
|
95
107
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -131,7 +143,12 @@ export function createCantonProvider({
|
|
|
131
143
|
tokenProvider,
|
|
132
144
|
});
|
|
133
145
|
|
|
134
|
-
return {
|
|
146
|
+
return {
|
|
147
|
+
client,
|
|
148
|
+
grpcClient,
|
|
149
|
+
tokenProvider,
|
|
150
|
+
walletUrl: params.walletUrl,
|
|
151
|
+
};
|
|
135
152
|
}
|
|
136
153
|
|
|
137
154
|
function createTokenProvider(params: CantonUriParams, isLocal: boolean): TokenProvider {
|
|
@@ -143,8 +160,7 @@ function createTokenProvider(params: CantonUriParams, isLocal: boolean): TokenPr
|
|
|
143
160
|
});
|
|
144
161
|
}
|
|
145
162
|
|
|
146
|
-
// TODO: add other
|
|
147
|
-
// Non-local: require OAuth2 client credentials
|
|
163
|
+
// TODO(CANTON): add other prod auth methods (direct JWT passthrough, etc.).
|
|
148
164
|
if (!params.oauth2) {
|
|
149
165
|
throw new Error(
|
|
150
166
|
'Canton provider requires OAuth2 credentials (token-url, client-id, client-secret) in the provider URI',
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { mapValues } from 'es-toolkit';
|
|
2
|
+
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// Generic JSON-tree visitors
|
|
5
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Result of a leaf check: either the leaf has been replaced (with `value`),
|
|
9
|
+
* or `undefined` to leave it alone and recurse into its children.
|
|
10
|
+
*/
|
|
11
|
+
type LeafResult = { value: unknown } | undefined;
|
|
12
|
+
|
|
13
|
+
/** Walk a JSON value and rewrite leaves matched by `replace`; recursion stops at a swapped leaf. */
|
|
14
|
+
const visit = <T>(value: T, replace: (leaf: unknown) => LeafResult): T => {
|
|
15
|
+
const result = replace(value);
|
|
16
|
+
if (result) return result.value as T;
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
return value.map((item) => visit(item, replace)) as T;
|
|
19
|
+
}
|
|
20
|
+
if (value !== null && typeof value === 'object') {
|
|
21
|
+
return mapValues(value as Record<string, unknown>, (item) => visit(item, replace)) as T;
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** True if `predicate` matches any leaf or sub-value in the tree. */
|
|
27
|
+
const containsLeaf = (value: unknown, predicate: (leaf: unknown) => boolean): boolean => {
|
|
28
|
+
if (predicate(value)) return true;
|
|
29
|
+
if (Array.isArray(value)) return value.some((item) => containsLeaf(item, predicate));
|
|
30
|
+
return (
|
|
31
|
+
value !== null &&
|
|
32
|
+
typeof value === 'object' &&
|
|
33
|
+
Object.values(value).some((item) => containsLeaf(item, predicate))
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
38
|
+
// Sender placeholder
|
|
39
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Sentinel emitted in place of the sender `Party` when the sender is unknown at
|
|
43
|
+
* create time; substituted for the real party at sign time.
|
|
44
|
+
*/
|
|
45
|
+
export const CANTON_SENDER_PLACEHOLDER = '<<CANTON_SENDER_PLACEHOLDER>>';
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns true if `value` is the Canton sender placeholder.
|
|
49
|
+
*/
|
|
50
|
+
export const isCantonSenderPlaceholder = (value: string): boolean =>
|
|
51
|
+
value === CANTON_SENDER_PLACEHOLDER;
|
|
52
|
+
|
|
53
|
+
/** Replace every {@link CANTON_SENDER_PLACEHOLDER} in a command tree with the actual sender party ID. */
|
|
54
|
+
export const replaceCantonSenderPlaceholders = <T>(value: T, senderParty: string): T =>
|
|
55
|
+
visit(value, (leaf) =>
|
|
56
|
+
leaf === CANTON_SENDER_PLACEHOLDER ? { value: senderParty } : undefined,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
/** Returns true if the command tree contains the sender placeholder anywhere. */
|
|
60
|
+
export const containsCantonSenderPlaceholder = (value: unknown): boolean =>
|
|
61
|
+
containsLeaf(value, (leaf) => leaf === CANTON_SENDER_PLACEHOLDER);
|
|
62
|
+
|
|
63
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
// AmuletCids placeholder
|
|
65
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Sentinel emitted as the sole element of the `amuletCids` array
|
|
69
|
+
* (`amuletCids: [CANTON_AMULET_CIDS_PLACEHOLDER]`); substituted for the resolved
|
|
70
|
+
* sender's Amulet contract IDs at sign time.
|
|
71
|
+
*/
|
|
72
|
+
export const CANTON_AMULET_CIDS_PLACEHOLDER = '<<CANTON_AMULET_CIDS_PLACEHOLDER>>';
|
|
73
|
+
|
|
74
|
+
const isAmuletCidsPlaceholderArray = (value: unknown): value is [string] =>
|
|
75
|
+
Array.isArray(value) && value.length === 1 && value[0] === CANTON_AMULET_CIDS_PLACEHOLDER;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Returns true if the command tree contains an amulet-cids placeholder array
|
|
79
|
+
* anywhere — i.e. an array `[CANTON_AMULET_CIDS_PLACEHOLDER]`.
|
|
80
|
+
*/
|
|
81
|
+
export const containsCantonAmuletCidsPlaceholder = (value: unknown): boolean =>
|
|
82
|
+
containsLeaf(value, isAmuletCidsPlaceholderArray);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Recursively walks a JSON-serializable value and replaces every
|
|
86
|
+
* `[CANTON_AMULET_CIDS_PLACEHOLDER]` array with the supplied list of resolved
|
|
87
|
+
* Amulet contract IDs.
|
|
88
|
+
*/
|
|
89
|
+
export const replaceCantonAmuletCidsPlaceholder = <T>(value: T, amuletCids: string[]): T =>
|
|
90
|
+
visit(value, (leaf) =>
|
|
91
|
+
isAmuletCidsPlaceholderArray(leaf) ? { value: amuletCids } : undefined,
|
|
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));
|
package/src/transaction.ts
CHANGED
|
@@ -10,9 +10,8 @@ import type { PartialBy } from '@layerzerolabs/typescript-utils';
|
|
|
10
10
|
|
|
11
11
|
// === Component schemas ===
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// they carry arbitrary Daml values whose shape depends on the template.
|
|
13
|
+
// Payload fields (createArguments, choiceArgument, contractKey) are z.any() —
|
|
14
|
+
// arbitrary Daml values whose shape depends on the template.
|
|
16
15
|
|
|
17
16
|
const createCommandSchema = z.object({
|
|
18
17
|
templateId: z.string(),
|
|
@@ -54,8 +53,43 @@ export const cantonDisclosedContractSchema = z.object({
|
|
|
54
53
|
synchronizerId: z.string(),
|
|
55
54
|
});
|
|
56
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
|
+
|
|
57
91
|
/** Output of prepareForSigning — needed by submitSigned to execute the transaction. */
|
|
58
|
-
const
|
|
92
|
+
const cantonInflightTransactionSchema = z.object({
|
|
59
93
|
/** The prepared transaction blob */
|
|
60
94
|
preparedTransaction: z.string(),
|
|
61
95
|
/** Hash of the prepared transaction (what was signed) */
|
|
@@ -67,6 +101,10 @@ const _cantonInflightTransactionSchema = z.object({
|
|
|
67
101
|
]),
|
|
68
102
|
/** Command ID for tracking */
|
|
69
103
|
commandId: z.string(),
|
|
104
|
+
/** Ledger offset at which the submission landed — used as `beginExclusive`
|
|
105
|
+
* for waitForCommand to avoid polling from the start of the ledger.
|
|
106
|
+
* Optional: only present after send(); absent for old/retry scenarios. */
|
|
107
|
+
completionOffset: z.number().optional(),
|
|
70
108
|
});
|
|
71
109
|
|
|
72
110
|
// === Lifecycle schemas ===
|
|
@@ -85,8 +123,16 @@ export const cantonTransactionSchema = transactionSchema.extend({
|
|
|
85
123
|
commands: z.array(cantonCommandSchema),
|
|
86
124
|
/** Disclosed contracts for contract/key lookups */
|
|
87
125
|
disclosedContracts: z.array(cantonDisclosedContractSchema),
|
|
88
|
-
/** Maps each actAs party
|
|
89
|
-
|
|
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(),
|
|
90
136
|
}),
|
|
91
137
|
});
|
|
92
138
|
|
|
@@ -95,7 +141,7 @@ export const cantonTransactionSchema = transactionSchema.extend({
|
|
|
95
141
|
*/
|
|
96
142
|
export const cantonAssignedTransactionSchema = assignedTransactionSchema.extend({
|
|
97
143
|
...cantonTransactionSchema.shape,
|
|
98
|
-
inflightTransaction:
|
|
144
|
+
inflightTransaction: cantonInflightTransactionSchema.optional(),
|
|
99
145
|
});
|
|
100
146
|
|
|
101
147
|
/**
|
|
@@ -126,7 +172,7 @@ export const cantonSignedTransactionSchema = signedTransactionSchema.extend({
|
|
|
126
172
|
*/
|
|
127
173
|
export const cantonMinedTransactionSchema = minedTransactionSchema.extend({
|
|
128
174
|
...cantonSignedTransactionSchema.shape,
|
|
129
|
-
inflightTransaction:
|
|
175
|
+
inflightTransaction: cantonInflightTransactionSchema,
|
|
130
176
|
});
|
|
131
177
|
|
|
132
178
|
// === Types ===
|
package/src/types.ts
CHANGED
|
@@ -106,6 +106,39 @@ export type ExternalSignature = {
|
|
|
106
106
|
signingAlgorithmSpec: string;
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* A right granted to a Canton user, as returned by `/v2/users/{userId}/rights`.
|
|
111
|
+
*
|
|
112
|
+
* The `kind` is a discriminated union — only one variant is set per right:
|
|
113
|
+
* - `CanActAs.value.party`: user can submit transactions as that party
|
|
114
|
+
* - `CanReadAs.value.party`: user can read events visible to that party
|
|
115
|
+
* - `ParticipantAdmin`: user has admin rights on the participant
|
|
116
|
+
* - `IdentityProviderAdmin`: user can administer its identity provider
|
|
117
|
+
* - `CanReadAsAnyParty`: user can read as any party
|
|
118
|
+
* - `CanExecuteAsAnyParty`: user can submit as any party
|
|
119
|
+
*
|
|
120
|
+
* Hand-rolled because the OpenAPI generator's `Kind` converter is broken
|
|
121
|
+
* (`instanceOfKindOneOf` checks lowercase `canActAs`, but `KindOneOfFromJSON`
|
|
122
|
+
* reads uppercase `CanActAs`), so the typed client strips all party data.
|
|
123
|
+
*
|
|
124
|
+
* The four nullary variants carry `value: unknown` because Canton's wire
|
|
125
|
+
* format for them is literally `{ "value": {} }` (see
|
|
126
|
+
* https://docs.digitalasset.com/build/3.4/explanations/json-api/) and we
|
|
127
|
+
* never read into that payload — only the presence of the variant matters.
|
|
128
|
+
*/
|
|
129
|
+
export type UserRightKind = {
|
|
130
|
+
CanActAs?: { value: { party: string } };
|
|
131
|
+
CanReadAs?: { value: { party: string } };
|
|
132
|
+
ParticipantAdmin?: { value: unknown };
|
|
133
|
+
IdentityProviderAdmin?: { value: unknown };
|
|
134
|
+
CanReadAsAnyParty?: { value: unknown };
|
|
135
|
+
CanExecuteAsAnyParty?: { value: unknown };
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export type UserRight = {
|
|
139
|
+
kind: UserRightKind;
|
|
140
|
+
};
|
|
141
|
+
|
|
109
142
|
/** Normalized active contract (flat shape derived from JsActiveContract). */
|
|
110
143
|
export type NormalizedActiveContract = {
|
|
111
144
|
contractId: string;
|
package/dist/CJEDJ6BA.js.map
DELETED
|
@@ -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","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":"CJEDJ6BA.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// Daml command schemas mirror the OpenAPI-generated Command union (Command = CommandOneOf | ... | CommandOneOf3).\n// Payload fields (createArguments, choiceArgument, contractKey) are z.any() because\n// they carry 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});\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 → senderEntityName that controls its signing key */\n partyToSenderEntity: z.record(z.string(), z.string()),\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"]}
|
package/dist/CTDZ456O.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.ts"],"names":["parseCantonUri","uri","url","URL","adminApiHost","searchParams","get","Error","userId","tokenUrl","undefined","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":"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","file":"CTDZ456O.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};\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 /** 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 // Extract Canton-specific params\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 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 // Remove Canton params to get clean JSON API URL\n for (const key of [\n 'admin-api',\n 'user-id',\n 'token-url',\n // TODO: check if these are acceptable in our providers config, we do the same with api-keys currently.\n 'client-id',\n 'client-secret',\n 'scope',\n 'audience',\n ]) {\n url.searchParams.delete(key);\n }\n\n // Reconstruct clean base URL (origin + pathname, plus any remaining query params)\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, 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 { client, grpcClient, tokenProvider };\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: add other authentication methods for prod: such as direct jwt passthrough, oauth2 client credentials, etc.\n // Non-local: require OAuth2 client credentials\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"]}
|