@layerzerolabs/common-canton 0.2.120 → 0.2.122
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 +800 -783
- package/.turbo/turbo-test.log +19 -50
- package/dist/{MFVQ6EHM.js → 22ZNNS3H.js} +3 -3
- package/dist/{MFVQ6EHM.js.map → 22ZNNS3H.js.map} +1 -1
- package/dist/{Q3RL6UXD.js → 2UWZKS5E.js} +4 -4
- package/dist/{Q3RL6UXD.js.map → 2UWZKS5E.js.map} +1 -1
- package/dist/{CAJCIAM3.js → 333Q6X6C.js} +3 -3
- package/dist/{CAJCIAM3.js.map → 333Q6X6C.js.map} +1 -1
- package/dist/{HRZTWWO4.js → 3ESWXEO3.js} +3 -3
- package/dist/{HRZTWWO4.js.map → 3ESWXEO3.js.map} +1 -1
- package/dist/{AYF4OAKH.js → 4G6A7TFX.js} +4 -4
- package/dist/4G6A7TFX.js.map +1 -0
- package/dist/{5OA7RJHH.js → 4PEF77PU.js} +3 -3
- package/dist/{5OA7RJHH.js.map → 4PEF77PU.js.map} +1 -1
- package/dist/{M5WKPPPH.js → 4SOUDUP7.js} +3 -3
- package/dist/{M5WKPPPH.js.map → 4SOUDUP7.js.map} +1 -1
- package/dist/4WZTQJXP.js +30 -0
- package/dist/4WZTQJXP.js.map +1 -0
- package/dist/{QYQWHMQM.js → 5KFMHJZB.js} +3 -3
- package/dist/{QYQWHMQM.js.map → 5KFMHJZB.js.map} +1 -1
- package/dist/7JX6NIYS.js +3 -0
- package/dist/7JX6NIYS.js.map +1 -0
- package/dist/{BL22CZFA.js → A2ZXPTGE.js} +4 -4
- package/dist/{BL22CZFA.js.map → A2ZXPTGE.js.map} +1 -1
- package/dist/{3T46OKQU.js → AVC5GQFU.js} +3 -3
- package/dist/{3T46OKQU.js.map → AVC5GQFU.js.map} +1 -1
- package/dist/{45YQNHS2.js → BHESIRKK.js} +3 -3
- package/dist/{45YQNHS2.js.map → BHESIRKK.js.map} +1 -1
- package/dist/CXQSVBVW.js +67 -0
- package/dist/CXQSVBVW.js.map +1 -0
- package/dist/{WXYN3MFC.js → CYZU3DTJ.js} +3 -3
- package/dist/{WXYN3MFC.js.map → CYZU3DTJ.js.map} +1 -1
- package/dist/{LL7Z56UN.js → D3AV6J7R.js} +3 -3
- package/dist/{LL7Z56UN.js.map → D3AV6J7R.js.map} +1 -1
- package/dist/{EWDK2D2A.js → DDAINXFD.js} +3 -3
- package/dist/{EWDK2D2A.js.map → DDAINXFD.js.map} +1 -1
- package/dist/{JSG7MGHH.js → EPHLTMJZ.js} +3 -3
- package/dist/{JSG7MGHH.js.map → EPHLTMJZ.js.map} +1 -1
- package/dist/{ZPOY5WJ2.js → FZGCL63V.js} +3 -3
- package/dist/{ZPOY5WJ2.js.map → FZGCL63V.js.map} +1 -1
- package/dist/{KBZ6YXX4.js → GHWJBJNB.js} +3 -3
- package/dist/{KBZ6YXX4.js.map → GHWJBJNB.js.map} +1 -1
- package/dist/{7GI6QGS6.js → H3BWRDYY.js} +3 -3
- package/dist/{7GI6QGS6.js.map → H3BWRDYY.js.map} +1 -1
- package/dist/{WSLU3JGO.js → HU7X7G5L.js} +3 -3
- package/dist/{WSLU3JGO.js.map → HU7X7G5L.js.map} +1 -1
- package/dist/{7IWE7Y2N.js → JA7BSC7C.js} +4 -4
- package/dist/{7IWE7Y2N.js.map → JA7BSC7C.js.map} +1 -1
- package/dist/{JXKVPYCE.js → JH2I4JGJ.js} +3 -3
- package/dist/{JXKVPYCE.js.map → JH2I4JGJ.js.map} +1 -1
- package/dist/{WHTAP4A3.js → JJKMXRP7.js} +9 -7
- package/dist/JJKMXRP7.js.map +1 -0
- package/dist/{7STDATVZ.js → JUZKQC2G.js} +3 -3
- package/dist/{7STDATVZ.js.map → JUZKQC2G.js.map} +1 -1
- package/dist/{QZJONP6W.js → KCFOSGPU.js} +3 -3
- package/dist/{QZJONP6W.js.map → KCFOSGPU.js.map} +1 -1
- package/dist/{4GYCD3G4.js → KIQAFHKC.js} +3 -3
- package/dist/{4GYCD3G4.js.map → KIQAFHKC.js.map} +1 -1
- package/dist/{FXR2Z54G.js → KJRFPBY4.js} +3 -3
- package/dist/{FXR2Z54G.js.map → KJRFPBY4.js.map} +1 -1
- package/dist/M3GPMXME.js +12 -0
- package/dist/M3GPMXME.js.map +1 -0
- package/dist/{AMLJTQWB.js → N3INXXRG.js} +3 -3
- package/dist/{AMLJTQWB.js.map → N3INXXRG.js.map} +1 -1
- package/dist/{GSEDMLUC.js → NJW7UX2A.js} +3 -3
- package/dist/{GSEDMLUC.js.map → NJW7UX2A.js.map} +1 -1
- package/dist/{KTNEUXUI.js → NRGCZ4DG.js} +5 -5
- package/dist/{KTNEUXUI.js.map → NRGCZ4DG.js.map} +1 -1
- package/dist/NRSV2VHQ.js +335 -0
- package/dist/NRSV2VHQ.js.map +1 -0
- package/dist/{DAP5XJGH.js → NX67V54F.js} +3 -3
- package/dist/{DAP5XJGH.js.map → NX67V54F.js.map} +1 -1
- package/dist/{UBHUOSK3.js → OIFJOKIO.js} +3 -3
- package/dist/{UBHUOSK3.js.map → OIFJOKIO.js.map} +1 -1
- package/dist/{NKXEPWZV.js → OO73Z5K6.js} +4 -4
- package/dist/{NKXEPWZV.js.map → OO73Z5K6.js.map} +1 -1
- package/dist/{2UKHG3HM.js → OUEL7K27.js} +3 -3
- package/dist/{2UKHG3HM.js.map → OUEL7K27.js.map} +1 -1
- package/dist/{KH7RP6Q4.js → OWXOYIMA.js} +3 -3
- package/dist/{KH7RP6Q4.js.map → OWXOYIMA.js.map} +1 -1
- package/dist/{CLAE73FR.js → OZZHAISY.js} +3 -3
- package/dist/{CLAE73FR.js.map → OZZHAISY.js.map} +1 -1
- package/dist/{IIQYRITU.js → PDIG5OUV.js} +3 -3
- package/dist/{IIQYRITU.js.map → PDIG5OUV.js.map} +1 -1
- package/dist/QAKOQQ7E.js +71 -0
- package/dist/QAKOQQ7E.js.map +1 -0
- package/dist/{NS763D57.js → QJMVWOLL.js} +3 -3
- package/dist/{NS763D57.js.map → QJMVWOLL.js.map} +1 -1
- package/dist/{KVXEYMWG.js → QNO3456Y.js} +3 -3
- package/dist/{KVXEYMWG.js.map → QNO3456Y.js.map} +1 -1
- package/dist/{TDLALQCM.js → R5PCNLRD.js} +3 -3
- package/dist/{TDLALQCM.js.map → R5PCNLRD.js.map} +1 -1
- package/dist/{K2SFNQJC.js → RHNMCG3C.js} +4 -4
- package/dist/{K2SFNQJC.js.map → RHNMCG3C.js.map} +1 -1
- package/dist/RVQWP4JU.js +76 -0
- package/dist/RVQWP4JU.js.map +1 -0
- package/dist/{73I7CBP3.js → SNDN7G42.js} +3 -3
- package/dist/{73I7CBP3.js.map → SNDN7G42.js.map} +1 -1
- package/dist/{ALC4M7WK.js → T4AL4FJH.js} +3 -3
- package/dist/{ALC4M7WK.js.map → T4AL4FJH.js.map} +1 -1
- package/dist/{5HH7PZW3.js → TZTIULG5.js} +29 -29
- package/dist/{5HH7PZW3.js.map → TZTIULG5.js.map} +1 -1
- package/dist/{5E77SJL7.js → VT3WUH5Q.js} +8 -7
- package/dist/VT3WUH5Q.js.map +1 -0
- package/dist/WKC6X2E3.js +27 -0
- package/dist/WKC6X2E3.js.map +1 -0
- package/dist/WLV6EHDB.js +60 -0
- package/dist/WLV6EHDB.js.map +1 -0
- package/dist/{HLWLB4AY.js → WUXXJWII.js} +3 -3
- package/dist/{HLWLB4AY.js.map → WUXXJWII.js.map} +1 -1
- package/dist/client/amulet.d.ts.map +1 -1
- package/dist/client/amulet.js +1 -1
- package/dist/client/canton-client.js +125 -125
- package/dist/client/grpc.d.ts +104 -18
- package/dist/client/grpc.d.ts.map +1 -1
- package/dist/client/grpc.js +7 -1
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +132 -128
- package/dist/client/topology/mappings.d.ts +53 -0
- package/dist/client/topology/mappings.d.ts.map +1 -0
- package/dist/client/topology/mappings.js +6 -0
- package/dist/client/topology/mappings.js.map +1 -0
- package/dist/client/topology/signing.d.ts +23 -0
- package/dist/client/topology/signing.d.ts.map +1 -0
- package/dist/client/topology/signing.js +4 -0
- package/dist/client/topology/signing.js.map +1 -0
- package/dist/client/topology/synchronizer-connectivity.d.ts +26 -0
- package/dist/client/topology/synchronizer-connectivity.d.ts.map +1 -0
- package/dist/client/topology/synchronizer-connectivity.js +4 -0
- package/dist/client/topology/synchronizer-connectivity.js.map +1 -0
- package/dist/client/topology/types.d.ts +120 -0
- package/dist/client/topology/types.d.ts.map +1 -0
- package/dist/client/topology/types.js +3 -0
- package/dist/client/topology/types.js.map +1 -0
- package/dist/client/topology/utils.d.ts +38 -0
- package/dist/client/topology/utils.d.ts.map +1 -0
- package/dist/client/topology/utils.js +6 -0
- package/dist/client/topology/utils.js.map +1 -0
- package/dist/client/utils.d.ts +17 -0
- package/dist/client/utils.d.ts.map +1 -1
- package/dist/client/utils.js +1 -1
- package/dist/events.js +2 -2
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +141 -136
- package/dist/minFee.d.ts +6 -0
- package/dist/minFee.d.ts.map +1 -0
- package/dist/minFee.js +5 -0
- package/dist/minFee.js.map +1 -0
- package/dist/open-api/apis/DefaultApi.js +123 -123
- package/dist/open-api/apis/index.js +123 -123
- package/dist/open-api/index.js +123 -123
- package/dist/open-api/models/Command.js +3 -3
- 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 +5 -5
- package/dist/open-api/models/CompletionResponseOneOf.js +1 -1
- package/dist/open-api/models/CompletionStreamResponse.js +5 -5
- package/dist/open-api/models/CreateUserRequest.js +7 -7
- package/dist/open-api/models/CumulativeFilter.js +2 -2
- package/dist/open-api/models/DeduplicationPeriod.js +1 -1
- package/dist/open-api/models/DeduplicationPeriod1.js +1 -1
- package/dist/open-api/models/DeduplicationPeriod2.js +2 -2
- package/dist/open-api/models/EventFormat.js +2 -2
- package/dist/open-api/models/FeaturesDescriptor.js +2 -2
- package/dist/open-api/models/Filters.js +2 -2
- package/dist/open-api/models/GetActiveContractsRequest.js +2 -2
- package/dist/open-api/models/GetEventsByContractIdRequest.js +2 -2
- package/dist/open-api/models/GetLedgerApiVersionResponse.js +3 -3
- package/dist/open-api/models/GetTransactionByIdRequest.js +2 -2
- package/dist/open-api/models/GetTransactionByOffsetRequest.js +2 -2
- package/dist/open-api/models/GetUpdateByIdRequest.js +2 -2
- package/dist/open-api/models/GetUpdateByOffsetRequest.js +2 -2
- package/dist/open-api/models/GetUpdatesRequest.js +2 -2
- package/dist/open-api/models/GrantUserRightsRequest.js +7 -7
- package/dist/open-api/models/GrantUserRightsResponse.js +7 -7
- package/dist/open-api/models/IdentifierFilter.js +2 -2
- package/dist/open-api/models/JsCommands.js +5 -5
- package/dist/open-api/models/JsExecuteSubmissionAndWaitForTransactionRequest.js +5 -5
- package/dist/open-api/models/JsExecuteSubmissionAndWaitRequest.js +3 -3
- package/dist/open-api/models/JsExecuteSubmissionRequest.js +3 -3
- package/dist/open-api/models/JsGetUpdateResponse.js +19 -19
- package/dist/open-api/models/JsGetUpdateTreesResponse.js +10 -10
- package/dist/open-api/models/JsGetUpdatesResponse.js +19 -19
- package/dist/open-api/models/JsPrepareSubmissionRequest.js +5 -5
- package/dist/open-api/models/JsReassignment.js +4 -4
- package/dist/open-api/models/JsReassignmentEvent.js +3 -3
- package/dist/open-api/models/JsSubmitAndWaitForReassignmentResponse.js +5 -5
- package/dist/open-api/models/JsSubmitAndWaitForTransactionRequest.js +8 -8
- package/dist/open-api/models/JsTopologyTransaction.js +7 -7
- package/dist/open-api/models/Kind.js +5 -5
- package/dist/open-api/models/ListUserRightsResponse.js +7 -7
- package/dist/open-api/models/Operation.js +4 -4
- package/dist/open-api/models/Reassignment.js +5 -5
- package/dist/open-api/models/Reassignment1.js +5 -5
- package/dist/open-api/models/RevokeUserRightsRequest.js +7 -7
- package/dist/open-api/models/RevokeUserRightsResponse.js +7 -7
- package/dist/open-api/models/Right.js +6 -6
- package/dist/open-api/models/SubmitAndWaitForReassignmentRequest.js +2 -2
- package/dist/open-api/models/TopologyEvent.js +6 -6
- package/dist/open-api/models/TopologyEventEvent.js +5 -5
- package/dist/open-api/models/TopologyTransaction.js +8 -8
- package/dist/open-api/models/TransactionFilter.js +2 -2
- package/dist/open-api/models/TransactionFormat.js +2 -2
- package/dist/open-api/models/Update.js +18 -18
- package/dist/open-api/models/Update1.js +9 -9
- package/dist/open-api/models/Update1OneOf1.js +6 -6
- package/dist/open-api/models/UpdateFormat.js +2 -2
- package/dist/open-api/models/UpdateOneOf1.js +6 -6
- package/dist/open-api/models/UpdateOneOf2.js +9 -9
- package/dist/open-api/models/UpdateVettedPackagesRequest.js +6 -6
- package/dist/open-api/models/VettedPackagesChange.js +5 -5
- package/dist/open-api/models/index.js +122 -122
- package/dist/provider.d.ts +3 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +132 -127
- package/dist/refresh/index.js +2 -2
- package/dist/refresh/resolve.js +2 -2
- package/dist/sdk/index.d.ts +0 -1
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/transaction.d.ts +353 -144
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/package.json +12 -10
- package/src/client/amulet.ts +5 -2
- package/src/client/grpc.ts +396 -39
- package/src/client/index.ts +20 -0
- package/src/client/topology/mappings.ts +152 -0
- package/src/client/topology/signing.ts +56 -0
- package/src/client/topology/synchronizer-connectivity.ts +110 -0
- package/src/client/topology/types.ts +133 -0
- package/src/client/topology/utils.ts +93 -0
- package/src/client/utils.ts +47 -9
- package/src/index.ts +5 -29
- package/src/minFee.ts +12 -0
- package/src/provider.ts +11 -3
- package/src/sdk/index.ts +0 -1
- package/src/transaction.ts +25 -4
- package/src/types.ts +15 -0
- package/test/client/amulet.test.ts +64 -0
- package/test/provider.test.ts +22 -0
- package/dist/5E77SJL7.js.map +0 -1
- package/dist/AYF4OAKH.js.map +0 -1
- package/dist/F42TZTWJ.js +0 -33
- package/dist/F42TZTWJ.js.map +0 -1
- package/dist/PQI7CWCR.js +0 -19
- package/dist/PQI7CWCR.js.map +0 -1
- package/dist/WHTAP4A3.js.map +0 -1
- package/dist/XE6H2SH4.js +0 -3
- package/dist/XE6H2SH4.js.map +0 -1
- package/dist/YHW7AKHX.js +0 -62
- package/dist/YHW7AKHX.js.map +0 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CryptoKeyFormat,
|
|
3
|
+
DecentralizedNamespaceDefinition,
|
|
4
|
+
Enums_ParticipantPermission,
|
|
5
|
+
NamespaceDelegation,
|
|
6
|
+
PartyToKeyMapping,
|
|
7
|
+
PartyToParticipant,
|
|
8
|
+
PartyToParticipant_HostingParticipant,
|
|
9
|
+
SigningKeySpec,
|
|
10
|
+
SigningKeyUsage,
|
|
11
|
+
SigningPublicKey,
|
|
12
|
+
TopologyMapping,
|
|
13
|
+
} from '@canton-network/core-ledger-proto';
|
|
14
|
+
|
|
15
|
+
import { computePublicKeyFingerprint } from '../utils';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Builds a Canton protocol `SigningPublicKey` from a DER-encoded secp256k1 public key.
|
|
19
|
+
*
|
|
20
|
+
* Keys use X.509 SubjectPublicKeyInfo encoding with `NAMESPACE` and `PROTOCOL` usage,
|
|
21
|
+
* as required by Canton topology mappings.
|
|
22
|
+
*
|
|
23
|
+
* @param publicKeyDer - DER-encoded secp256k1 public key (X.509 SubjectPublicKeyInfo).
|
|
24
|
+
* @returns A `SigningPublicKey` for use in topology mapping protobuf fields.
|
|
25
|
+
*/
|
|
26
|
+
function buildSigningPublicKey(publicKeyDer: Uint8Array): SigningPublicKey {
|
|
27
|
+
return SigningPublicKey.create({
|
|
28
|
+
format: CryptoKeyFormat.DER_X509_SUBJECT_PUBLIC_KEY_INFO,
|
|
29
|
+
publicKey: publicKeyDer,
|
|
30
|
+
usage: [SigningKeyUsage.NAMESPACE, SigningKeyUsage.PROTOCOL],
|
|
31
|
+
keySpec: SigningKeySpec.EC_SECP256K1,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Builds a Namespace Delegation (NSD) topology mapping for a root owner key.
|
|
37
|
+
*
|
|
38
|
+
* Registers a self-rooted namespace: the namespace identifier is the public key
|
|
39
|
+
* fingerprint, and the same key is the root delegation target. The unsigned
|
|
40
|
+
* transaction produced from this mapping must be signed by that key alone.
|
|
41
|
+
*
|
|
42
|
+
* @param publicKeyDer - DER-encoded secp256k1 public key for the namespace owner.
|
|
43
|
+
* @returns A `TopologyMapping` containing a root `NamespaceDelegation`.
|
|
44
|
+
*/
|
|
45
|
+
export function buildNamespaceDelegationMapping(publicKeyDer: Uint8Array): TopologyMapping {
|
|
46
|
+
const namespace = computePublicKeyFingerprint(publicKeyDer);
|
|
47
|
+
return TopologyMapping.create({
|
|
48
|
+
mapping: {
|
|
49
|
+
oneofKind: 'namespaceDelegation',
|
|
50
|
+
namespaceDelegation: NamespaceDelegation.create({
|
|
51
|
+
namespace,
|
|
52
|
+
targetKey: buildSigningPublicKey(publicKeyDer),
|
|
53
|
+
isRootDelegation: true,
|
|
54
|
+
}),
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Builds a Decentralized Namespace Definition (DND) topology mapping.
|
|
61
|
+
*
|
|
62
|
+
* Defines a multi-owner namespace identified by `decentralizedNamespace`, with a
|
|
63
|
+
* signing threshold over the listed owner key fingerprints. Every owner must
|
|
64
|
+
* authorize the transaction.
|
|
65
|
+
*
|
|
66
|
+
* @param decentralizedNamespace - Decentralized namespace fingerprint (e.g. `1220…`).
|
|
67
|
+
* @param threshold - Minimum number of owner signatures required (≤ `owners.length`).
|
|
68
|
+
* @param owners - Owner namespace fingerprints (multihash hex strings).
|
|
69
|
+
* @returns A `TopologyMapping` containing a `DecentralizedNamespaceDefinition`.
|
|
70
|
+
*/
|
|
71
|
+
export function buildDecentralizedNamespaceDefinitionMapping(
|
|
72
|
+
decentralizedNamespace: string,
|
|
73
|
+
threshold: number,
|
|
74
|
+
owners: string[],
|
|
75
|
+
): TopologyMapping {
|
|
76
|
+
return TopologyMapping.create({
|
|
77
|
+
mapping: {
|
|
78
|
+
oneofKind: 'decentralizedNamespaceDefinition',
|
|
79
|
+
decentralizedNamespaceDefinition: DecentralizedNamespaceDefinition.create({
|
|
80
|
+
decentralizedNamespace,
|
|
81
|
+
threshold,
|
|
82
|
+
owners,
|
|
83
|
+
}),
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Builds a Party-to-Key (PTK) topology mapping.
|
|
90
|
+
*
|
|
91
|
+
* Binds signing keys to a party and sets the threshold required to authorize
|
|
92
|
+
* party-level topology changes. Decentralized namespace owners must co-sign
|
|
93
|
+
* the transaction.
|
|
94
|
+
*
|
|
95
|
+
* @param partyId - Full party identifier (e.g. `hint::1220…`).
|
|
96
|
+
* @param signingPublicKeyDers - DER-encoded signing public keys assigned to the party.
|
|
97
|
+
* @param threshold - Minimum number of party signing keys required (≤ number of keys).
|
|
98
|
+
* @returns A `TopologyMapping` containing a `PartyToKeyMapping`.
|
|
99
|
+
*/
|
|
100
|
+
export function buildPartyToKeyMapping(
|
|
101
|
+
partyId: string,
|
|
102
|
+
signingPublicKeyDers: Uint8Array[],
|
|
103
|
+
threshold: number,
|
|
104
|
+
): TopologyMapping {
|
|
105
|
+
return TopologyMapping.create({
|
|
106
|
+
mapping: {
|
|
107
|
+
oneofKind: 'partyToKeyMapping',
|
|
108
|
+
partyToKeyMapping: PartyToKeyMapping.create({
|
|
109
|
+
party: partyId,
|
|
110
|
+
threshold,
|
|
111
|
+
signingKeys: signingPublicKeyDers.map((publicKeyDer) =>
|
|
112
|
+
buildSigningPublicKey(publicKeyDer),
|
|
113
|
+
),
|
|
114
|
+
}),
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Builds a Party-to-Participant (PTP) topology mapping.
|
|
121
|
+
*
|
|
122
|
+
* Declares which participant nodes host the party. Each participant is granted
|
|
123
|
+
* `CONFIRMATION` permission. On initial hosting, submit the signed transaction
|
|
124
|
+
* with `proposal: true` so the participant can complete authorization via the
|
|
125
|
+
* topology `Authorize` RPC.
|
|
126
|
+
*
|
|
127
|
+
* @param partyId - Full party identifier (e.g. `hint::1220…`).
|
|
128
|
+
* @param participantIds - Participant UIDs that should host the party.
|
|
129
|
+
* @param threshold - Hosting threshold (≤ `participantIds.length`).
|
|
130
|
+
* @returns A `TopologyMapping` containing a `PartyToParticipant` mapping.
|
|
131
|
+
*/
|
|
132
|
+
export function buildPartyToParticipantMapping(
|
|
133
|
+
partyId: string,
|
|
134
|
+
participantIds: string[],
|
|
135
|
+
threshold: number,
|
|
136
|
+
): TopologyMapping {
|
|
137
|
+
return TopologyMapping.create({
|
|
138
|
+
mapping: {
|
|
139
|
+
oneofKind: 'partyToParticipant',
|
|
140
|
+
partyToParticipant: PartyToParticipant.create({
|
|
141
|
+
party: partyId,
|
|
142
|
+
threshold,
|
|
143
|
+
participants: participantIds.map((participantId) =>
|
|
144
|
+
PartyToParticipant_HostingParticipant.create({
|
|
145
|
+
participantUid: participantId,
|
|
146
|
+
permission: Enums_ParticipantPermission.CONFIRMATION,
|
|
147
|
+
}),
|
|
148
|
+
),
|
|
149
|
+
}),
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MultiTransactionSignatures,
|
|
3
|
+
Signature,
|
|
4
|
+
SignatureFormat,
|
|
5
|
+
SignedTopologyTransaction,
|
|
6
|
+
SigningAlgorithmSpec,
|
|
7
|
+
} from '@canton-network/core-ledger-proto';
|
|
8
|
+
|
|
9
|
+
/** A single namespace-key signature over the multi-transaction hash. */
|
|
10
|
+
export type TopologySignature = {
|
|
11
|
+
/** Fingerprint of the signing key (Canton `signedBy`). */
|
|
12
|
+
signerFingerprint: string;
|
|
13
|
+
/** Raw DER ECDSA-SHA256 signature bytes over the multi-transaction hash. */
|
|
14
|
+
signatureBytes: Uint8Array;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Wraps namespace-key signatures over one or more topology transaction hashes.
|
|
19
|
+
*
|
|
20
|
+
* Use with {@link computeMultiTransactionHash}: sign the multi-hash once per key,
|
|
21
|
+
* then pass the raw signatures here to cover every hash in the batch.
|
|
22
|
+
*/
|
|
23
|
+
export function buildMultiTransactionSignatures(
|
|
24
|
+
transactionHashes: Uint8Array[],
|
|
25
|
+
signatures: readonly TopologySignature[],
|
|
26
|
+
): MultiTransactionSignatures {
|
|
27
|
+
return MultiTransactionSignatures.create({
|
|
28
|
+
transactionHashes,
|
|
29
|
+
signatures: signatures.map((entry) =>
|
|
30
|
+
Signature.create({
|
|
31
|
+
format: SignatureFormat.DER,
|
|
32
|
+
signature: entry.signatureBytes,
|
|
33
|
+
signedBy: entry.signerFingerprint,
|
|
34
|
+
signingAlgorithmSpec: SigningAlgorithmSpec.EC_DSA_SHA_256,
|
|
35
|
+
}),
|
|
36
|
+
),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Builds a {@link SignedTopologyTransaction} ready for
|
|
42
|
+
* {@link CantonGrpcClient.submitTopologyTransactions}.
|
|
43
|
+
*
|
|
44
|
+
* Set `proposal: true` when the hosting participant must authorize the mapping.
|
|
45
|
+
*/
|
|
46
|
+
export function buildSignedTransaction(
|
|
47
|
+
transaction: Uint8Array,
|
|
48
|
+
multiTransactionSignatures: MultiTransactionSignatures[],
|
|
49
|
+
proposal = false,
|
|
50
|
+
): SignedTopologyTransaction {
|
|
51
|
+
return SignedTopologyTransaction.create({
|
|
52
|
+
transaction,
|
|
53
|
+
multiTransactionSignatures,
|
|
54
|
+
proposal,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// `@protobuf-ts/runtime` and `@protobuf-ts/runtime-rpc` are already in the tree as
|
|
2
|
+
// transitive deps of `@canton-network/core-ledger-proto` (and `@protobuf-ts/grpc-transport`),
|
|
3
|
+
// so declaring them here adds no new dependency — pnpm's isolation just requires this
|
|
4
|
+
// package to list them before it can import them directly.
|
|
5
|
+
import { MessageType, RepeatType, ScalarType } from '@protobuf-ts/runtime';
|
|
6
|
+
import {
|
|
7
|
+
type MethodInfo,
|
|
8
|
+
type RpcOptions,
|
|
9
|
+
type RpcTransport,
|
|
10
|
+
ServiceType,
|
|
11
|
+
stackIntercept,
|
|
12
|
+
type UnaryCall,
|
|
13
|
+
} from '@protobuf-ts/runtime-rpc';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimal hand-written client for the Canton participant admin
|
|
17
|
+
* `SynchronizerConnectivityService.ListConnectedSynchronizers` RPC.
|
|
18
|
+
*
|
|
19
|
+
* The published `@canton-network/core-ledger-proto` package does not ship the
|
|
20
|
+
* `com.digitalasset.canton.admin.participant.v30` namespace, so the message and
|
|
21
|
+
* service descriptors required for synchronizer discovery are declared here
|
|
22
|
+
* against the same `@protobuf-ts` runtime the generated topology clients use.
|
|
23
|
+
*
|
|
24
|
+
* Field numbers mirror the `SynchronizerConnectivityService` definition in the
|
|
25
|
+
* Canton `com.digitalasset.canton.admin.participant.v30` proto package; re-verify
|
|
26
|
+
* them when bumping `@canton-network/core-ledger-proto` (pinned at ^0.22.0).
|
|
27
|
+
*
|
|
28
|
+
* TODO: the synchronizer id is also resolvable via the JSON Ledger API
|
|
29
|
+
* (`/v2/state/connected-synchronizers`), in which case this hand-written gRPC
|
|
30
|
+
* client can be removed — but consumers would then need to pass a JSON API URL too.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const SERVICE_NAME =
|
|
34
|
+
'com.digitalasset.canton.admin.participant.v30.SynchronizerConnectivityService';
|
|
35
|
+
|
|
36
|
+
/** Empty request for `ListConnectedSynchronizers`. */
|
|
37
|
+
export type ListConnectedSynchronizersRequest = Record<string, never>;
|
|
38
|
+
|
|
39
|
+
/** A single connected-synchronizer entry. */
|
|
40
|
+
export type ConnectedSynchronizer = {
|
|
41
|
+
/** Human-readable synchronizer alias (e.g. `global`). */
|
|
42
|
+
synchronizerAlias: string;
|
|
43
|
+
/** Logical synchronizer id — the value accepted by topology `BaseQuery.store`. */
|
|
44
|
+
synchronizerId: string;
|
|
45
|
+
/** Physical synchronizer id (logical id plus a `::<protocol>-<serial>` suffix). */
|
|
46
|
+
physicalSynchronizerId: string;
|
|
47
|
+
/** Whether the participant's connection to the synchronizer is healthy. */
|
|
48
|
+
healthy: boolean;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** Response for `ListConnectedSynchronizers`. */
|
|
52
|
+
export type ListConnectedSynchronizersResponse = {
|
|
53
|
+
connectedSynchronizers: ConnectedSynchronizer[];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const connectedSynchronizerMessage = new MessageType<ConnectedSynchronizer>(
|
|
57
|
+
`${SERVICE_NAME}.ListConnectedSynchronizersResponse.Result`,
|
|
58
|
+
[
|
|
59
|
+
{ no: 1, name: 'synchronizer_alias', kind: 'scalar', T: ScalarType.STRING },
|
|
60
|
+
{ no: 2, name: 'synchronizer_id', kind: 'scalar', T: ScalarType.STRING },
|
|
61
|
+
{ no: 3, name: 'physical_synchronizer_id', kind: 'scalar', T: ScalarType.STRING },
|
|
62
|
+
{ no: 4, name: 'healthy', kind: 'scalar', T: ScalarType.BOOL },
|
|
63
|
+
],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const requestMessage = new MessageType<ListConnectedSynchronizersRequest>(
|
|
67
|
+
`${SERVICE_NAME}.ListConnectedSynchronizersRequest`,
|
|
68
|
+
[],
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const responseMessage = new MessageType<ListConnectedSynchronizersResponse>(
|
|
72
|
+
`${SERVICE_NAME}.ListConnectedSynchronizersResponse`,
|
|
73
|
+
[
|
|
74
|
+
{
|
|
75
|
+
no: 1,
|
|
76
|
+
name: 'connected_synchronizers',
|
|
77
|
+
kind: 'message',
|
|
78
|
+
repeat: RepeatType.UNPACKED,
|
|
79
|
+
T: () => connectedSynchronizerMessage,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const service = new ServiceType(SERVICE_NAME, [
|
|
85
|
+
{ name: 'ListConnectedSynchronizers', options: {}, I: requestMessage, O: responseMessage },
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
/** Client for the participant admin `SynchronizerConnectivityService`. */
|
|
89
|
+
export class SynchronizerConnectivityServiceClient {
|
|
90
|
+
readonly #transport: RpcTransport;
|
|
91
|
+
|
|
92
|
+
constructor(transport: RpcTransport) {
|
|
93
|
+
this.#transport = transport;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Lists synchronizers the participant is currently connected to. */
|
|
97
|
+
listConnectedSynchronizers(
|
|
98
|
+
input: ListConnectedSynchronizersRequest,
|
|
99
|
+
options?: RpcOptions,
|
|
100
|
+
): UnaryCall<ListConnectedSynchronizersRequest, ListConnectedSynchronizersResponse> {
|
|
101
|
+
const method = service.methods[0] as MethodInfo<
|
|
102
|
+
ListConnectedSynchronizersRequest,
|
|
103
|
+
ListConnectedSynchronizersResponse
|
|
104
|
+
>;
|
|
105
|
+
return stackIntercept<
|
|
106
|
+
ListConnectedSynchronizersRequest,
|
|
107
|
+
ListConnectedSynchronizersResponse
|
|
108
|
+
>('unary', this.#transport, method, this.#transport.mergeOptions(options), input);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Enums_ParticipantPermission,
|
|
3
|
+
type GenerateTransactionsResponse_GeneratedTransaction,
|
|
4
|
+
} from '@canton-network/core-ledger-proto';
|
|
5
|
+
import type { ClientOptions } from '@grpc/grpc-js';
|
|
6
|
+
|
|
7
|
+
import type { TokenProvider } from '../../auth/token-provider';
|
|
8
|
+
|
|
9
|
+
/** Unsigned topology transaction from `GenerateTransactions` (`serializedTransaction`, `transactionHash`). */
|
|
10
|
+
export type GeneratedTopologyTransaction = GenerateTransactionsResponse_GeneratedTransaction;
|
|
11
|
+
|
|
12
|
+
/** Inputs for building an unsigned Namespace Delegation topology transaction. */
|
|
13
|
+
export type CreateNamespaceDelegationTxParams = {
|
|
14
|
+
/** DER-encoded secp256k1 public key (X.509 SubjectPublicKeyInfo). Namespace is derived from its fingerprint. */
|
|
15
|
+
publicKeyDer: Uint8Array;
|
|
16
|
+
/** Topology serial (default: 0 = auto-determined by Canton). */
|
|
17
|
+
serial?: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Inputs for building an unsigned Decentralized Namespace Definition topology transaction. */
|
|
21
|
+
export type CreateDecentralizedNamespaceDefinitionTxParams = {
|
|
22
|
+
/** Owner key fingerprints (multihash hex). Namespace id is derived from these. */
|
|
23
|
+
owners: string[];
|
|
24
|
+
/** Signing threshold (≤ number of owners). */
|
|
25
|
+
threshold: number;
|
|
26
|
+
/** Topology serial (default: 0 = auto-determined by Canton). */
|
|
27
|
+
serial?: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type UpdateDecentralizedNamespaceDefinitionTxParams =
|
|
31
|
+
CreateDecentralizedNamespaceDefinitionTxParams & {
|
|
32
|
+
namespace: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** Inputs for building an unsigned Party-to-Key mapping topology transaction. */
|
|
36
|
+
export type CreatePartyToKeyMappingTxParams = {
|
|
37
|
+
/** Full party id (e.g. `hint::1220…`). */
|
|
38
|
+
partyId: string;
|
|
39
|
+
/** DER-encoded signing public keys. */
|
|
40
|
+
signingPublicKeyDers: Uint8Array[];
|
|
41
|
+
/** Signing threshold (≤ number of keys). */
|
|
42
|
+
threshold: number;
|
|
43
|
+
/** Topology serial (default: 0 = auto-determined by Canton). */
|
|
44
|
+
serial?: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** Inputs for building an unsigned Party-to-Participant topology transaction. */
|
|
48
|
+
export type CreatePartyToParticipantMappingTxParams = {
|
|
49
|
+
/** Full party id (e.g. `hint::1220…`). */
|
|
50
|
+
partyId: string;
|
|
51
|
+
/** Hosting participant id(s). */
|
|
52
|
+
participantIds: string[];
|
|
53
|
+
/** Hosting threshold (≤ number of participants). */
|
|
54
|
+
threshold: number;
|
|
55
|
+
/** Topology serial (default: 0 = auto-determined by Canton). */
|
|
56
|
+
serial?: number;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** Namespace Delegation (NSD) as returned by topology list queries. */
|
|
60
|
+
export type NamespaceDelegationState = {
|
|
61
|
+
/** Namespace fingerprint this delegation applies to. */
|
|
62
|
+
namespace: string;
|
|
63
|
+
/** Fingerprint of the key receiving delegation authority. */
|
|
64
|
+
targetKeyFingerprint: string;
|
|
65
|
+
/** Whether this is a root (self) namespace delegation. */
|
|
66
|
+
isRootDelegation: boolean;
|
|
67
|
+
/** Topology serial of this mapping revision. */
|
|
68
|
+
serial: number;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** Decentralized Namespace Definition (DND) as returned by topology list queries. */
|
|
72
|
+
export type DecentralizedNamespaceDefinitionState = {
|
|
73
|
+
/** Decentralized namespace fingerprint. */
|
|
74
|
+
namespace: string;
|
|
75
|
+
/** Minimum number of owner signatures required. */
|
|
76
|
+
threshold: number;
|
|
77
|
+
/** Owner namespace fingerprints (multihash hex). */
|
|
78
|
+
owners: string[];
|
|
79
|
+
/** Topology serial of this mapping revision. */
|
|
80
|
+
serial: number;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/** Party-to-Key (PTK) mapping as returned by topology list queries. */
|
|
84
|
+
export type PartyToKeyMappingState = {
|
|
85
|
+
/** Full party identifier. */
|
|
86
|
+
party: string;
|
|
87
|
+
/** Minimum number of signing keys required. */
|
|
88
|
+
threshold: number;
|
|
89
|
+
/** Fingerprints of keys authorized to sign for the party. */
|
|
90
|
+
signingKeyFingerprints: string[];
|
|
91
|
+
/** Topology serial of this mapping revision. */
|
|
92
|
+
serial: number;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/** Party-to-Participant (PTP) mapping as returned by topology list queries. */
|
|
96
|
+
export type PartyToParticipantMappingState = {
|
|
97
|
+
/** Full party identifier. */
|
|
98
|
+
party: string;
|
|
99
|
+
/** Hosting threshold (≤ number of participants). */
|
|
100
|
+
threshold: number;
|
|
101
|
+
/** Participant nodes hosting the party and their permission. */
|
|
102
|
+
participants: { participantUid: string; permission: Enums_ParticipantPermission }[];
|
|
103
|
+
/** Topology serial of this mapping revision. */
|
|
104
|
+
serial: number;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/** TLS credentials for Canton admin gRPC connections. */
|
|
108
|
+
export type TlsOptions = {
|
|
109
|
+
/** CA root certificate for server verification. */
|
|
110
|
+
rootCert?: Buffer;
|
|
111
|
+
/** Client private key for mutual TLS. */
|
|
112
|
+
clientKey?: Buffer;
|
|
113
|
+
/** Client certificate for mutual TLS. */
|
|
114
|
+
clientCert?: Buffer;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/** Options for constructing a {@link CantonGrpcClient}. */
|
|
118
|
+
export type CantonGrpcClientOptions = {
|
|
119
|
+
/** Participant admin API host (e.g. `participant.example.com:443`). */
|
|
120
|
+
host: string;
|
|
121
|
+
/** Supplies a fresh Bearer token before each RPC call. */
|
|
122
|
+
tokenProvider: TokenProvider;
|
|
123
|
+
/**
|
|
124
|
+
* Logical synchronizer id used as the topology store. When omitted, the first
|
|
125
|
+
* synchronizer the participant is connected to (via `ListConnectedSynchronizers`)
|
|
126
|
+
* is resolved on the first RPC.
|
|
127
|
+
*/
|
|
128
|
+
synchronizerId?: string;
|
|
129
|
+
/** TLS options; omitted for insecure (non-:443) or default SSL on :443. */
|
|
130
|
+
tls?: TlsOptions;
|
|
131
|
+
/** Overrides the default gRPC channel options. */
|
|
132
|
+
grpcClientOptions?: ClientOptions;
|
|
133
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { BaseQuery, Empty, StoreId } from '@canton-network/core-ledger-proto';
|
|
2
|
+
import { ChannelCredentials } from '@grpc/grpc-js';
|
|
3
|
+
|
|
4
|
+
import { bytesToHex } from '@layerzerolabs/common-encoding-utils';
|
|
5
|
+
|
|
6
|
+
import { cantonMultihash } from '../utils';
|
|
7
|
+
import type { TlsOptions } from './types';
|
|
8
|
+
|
|
9
|
+
/** Canton hash purpose for decentralized namespace derivation. */
|
|
10
|
+
const HASH_PURPOSE_DECENTRALIZED_NAMESPACE = 37;
|
|
11
|
+
|
|
12
|
+
/** Canton hash purpose for multi-transaction topology signing. */
|
|
13
|
+
const HASH_PURPOSE_MULTI_TRANSACTION = 55;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Computes the decentralized namespace fingerprint from owner key fingerprints.
|
|
17
|
+
*
|
|
18
|
+
* Owners are sorted lexicographically, then hashed as
|
|
19
|
+
* `1220` + SHA256(purpose=37 || for each owner: len(utf8) || utf8).
|
|
20
|
+
*/
|
|
21
|
+
export function computeDecentralizedNamespace(owners: string[]): string {
|
|
22
|
+
const sorted = [...owners].sort();
|
|
23
|
+
const parts: Buffer[] = [];
|
|
24
|
+
for (const owner of sorted) {
|
|
25
|
+
const ownerBytes = Buffer.from(owner, 'utf-8');
|
|
26
|
+
const lengthPrefix = Buffer.alloc(4);
|
|
27
|
+
lengthPrefix.writeUInt32BE(ownerBytes.length);
|
|
28
|
+
parts.push(lengthPrefix, ownerBytes);
|
|
29
|
+
}
|
|
30
|
+
return bytesToHex(cantonMultihash(HASH_PURPOSE_DECENTRALIZED_NAMESPACE, Buffer.concat(parts)));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Combines topology transaction hashes into the digest Canton expects signed.
|
|
35
|
+
*
|
|
36
|
+
* Hashes are sorted lexicographically, count-prefixed, each length-prefixed, then
|
|
37
|
+
* hashed with purpose 55. Pass a single hash when signing one transaction —
|
|
38
|
+
* Canton always uses this multi-transaction format for `AddTransactions`.
|
|
39
|
+
*/
|
|
40
|
+
export function computeMultiTransactionHash(hashes: Uint8Array[]): Uint8Array {
|
|
41
|
+
const sorted = [...hashes].sort((left, right) =>
|
|
42
|
+
Buffer.compare(Buffer.from(left), Buffer.from(right)),
|
|
43
|
+
);
|
|
44
|
+
const parts: Buffer[] = [];
|
|
45
|
+
const countBuffer = Buffer.alloc(4);
|
|
46
|
+
countBuffer.writeUInt32BE(sorted.length);
|
|
47
|
+
parts.push(countBuffer);
|
|
48
|
+
for (const hash of sorted) {
|
|
49
|
+
const lengthBuffer = Buffer.alloc(4);
|
|
50
|
+
lengthBuffer.writeUInt32BE(hash.length);
|
|
51
|
+
parts.push(lengthBuffer, Buffer.from(hash));
|
|
52
|
+
}
|
|
53
|
+
return cantonMultihash(HASH_PURPOSE_MULTI_TRANSACTION, Buffer.concat(parts));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Builds a topology `StoreId` scoped to a synchronizer.
|
|
58
|
+
*
|
|
59
|
+
* Used as the `store` field on topology read/write RPC requests.
|
|
60
|
+
*/
|
|
61
|
+
export function synchronizerStore(synchronizerId: string): StoreId {
|
|
62
|
+
return StoreId.create({
|
|
63
|
+
store: { oneofKind: 'synchronizer', synchronizer: { id: synchronizerId } },
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Builds a topology `BaseQuery` at synchronizer head state.
|
|
69
|
+
*
|
|
70
|
+
* Used as the `baseQuery` field on topology list RPC requests.
|
|
71
|
+
*/
|
|
72
|
+
export function headStateBaseQuery(synchronizerId: string, proposals = false): BaseQuery {
|
|
73
|
+
return BaseQuery.create({
|
|
74
|
+
store: synchronizerStore(synchronizerId),
|
|
75
|
+
timeQuery: { oneofKind: 'headState', headState: Empty.create({}) },
|
|
76
|
+
proposals,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Builds gRPC channel credentials for the Canton admin API.
|
|
82
|
+
*
|
|
83
|
+
* Uses explicit TLS when `tls` is set, default SSL for hosts ending in `:443`,
|
|
84
|
+
* and insecure credentials otherwise.
|
|
85
|
+
*/
|
|
86
|
+
export function buildChannelCredentials(host: string, tls?: TlsOptions): ChannelCredentials {
|
|
87
|
+
if (tls) {
|
|
88
|
+
return ChannelCredentials.createSsl(tls.rootCert, tls.clientKey, tls.clientCert);
|
|
89
|
+
}
|
|
90
|
+
return host.endsWith(':443')
|
|
91
|
+
? ChannelCredentials.createSsl()
|
|
92
|
+
: ChannelCredentials.createInsecure();
|
|
93
|
+
}
|
package/src/client/utils.ts
CHANGED
|
@@ -14,8 +14,32 @@ export function extractTransactions(updates: CantonUpdate[]): CantonTransaction[
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const HASH_PURPOSE_PUBLIC_KEY_FINGERPRINT = 12;
|
|
17
|
+
const HASH_PURPOSE_DECENTRALIZED_NAMESPACE = 37;
|
|
17
18
|
const MULTIHASH_SHA256_PREFIX = new Uint8Array([0x12, 0x20]);
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Canton multihash: `0x1220 || SHA-256(BE32(purpose) || data)`.
|
|
22
|
+
*/
|
|
23
|
+
export function cantonMultihash(purpose: number, data: Uint8Array): Uint8Array {
|
|
24
|
+
const purposePrefix = new Uint8Array(4);
|
|
25
|
+
new DataView(purposePrefix.buffer).setUint32(0, purpose);
|
|
26
|
+
|
|
27
|
+
const hash = createHash('sha256').update(purposePrefix).update(data).digest();
|
|
28
|
+
|
|
29
|
+
const result = new Uint8Array(MULTIHASH_SHA256_PREFIX.length + hash.length);
|
|
30
|
+
result.set(MULTIHASH_SHA256_PREFIX);
|
|
31
|
+
result.set(hash, MULTIHASH_SHA256_PREFIX.length);
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Canton fingerprint for a DER-encoded public key (purpose 12).
|
|
37
|
+
* For root NSD, this is also the namespace id.
|
|
38
|
+
*/
|
|
39
|
+
export function computePublicKeyFingerprint(publicKeyDer: Uint8Array): string {
|
|
40
|
+
return bytesToHex(cantonMultihash(HASH_PURPOSE_PUBLIC_KEY_FINGERPRINT, publicKeyDer));
|
|
41
|
+
}
|
|
42
|
+
|
|
19
43
|
/**
|
|
20
44
|
* Computes the Canton fingerprint for an uncompressed secp256k1 public key.
|
|
21
45
|
* DER-encodes the key, then computes hex(SHA-256 multihash of purpose=12 || publicKeyDer).
|
|
@@ -27,14 +51,28 @@ export function computeCantonFingerprint(uncompressedPublicKey: Uint8Array): str
|
|
|
27
51
|
publicKeyDer.set(SECP256K1_SPKI_DER_HEADER);
|
|
28
52
|
publicKeyDer.set(uncompressedPublicKey, SECP256K1_SPKI_DER_HEADER.length);
|
|
29
53
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const hash = createHash('sha256').update(purposePrefix).update(publicKeyDer).digest();
|
|
34
|
-
|
|
35
|
-
const result = new Uint8Array(MULTIHASH_SHA256_PREFIX.length + hash.length);
|
|
36
|
-
result.set(MULTIHASH_SHA256_PREFIX);
|
|
37
|
-
result.set(hash, MULTIHASH_SHA256_PREFIX.length);
|
|
54
|
+
return computePublicKeyFingerprint(publicKeyDer);
|
|
55
|
+
}
|
|
38
56
|
|
|
39
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Deterministic decentralized-namespace fingerprint from owner key fingerprints.
|
|
59
|
+
* `"1220" + SHA256(purpose=37 || for each sorted owner: len(utf8) || utf8)`.
|
|
60
|
+
*
|
|
61
|
+
* For threshold-1 / single-owner namespaces this is `computeDecentralizedNamespace([keyFp])`,
|
|
62
|
+
* which is the party id suffix — not the raw key fingerprint.
|
|
63
|
+
*/
|
|
64
|
+
export function computeDecentralizedNamespace(owners: string[]): string {
|
|
65
|
+
const sorted = [...owners].map((owner) => owner.replace(/^0x/i, '')).sort();
|
|
66
|
+
const hash = createHash('sha256');
|
|
67
|
+
const purposeBuf = Buffer.alloc(4);
|
|
68
|
+
purposeBuf.writeUInt32BE(HASH_PURPOSE_DECENTRALIZED_NAMESPACE);
|
|
69
|
+
hash.update(purposeBuf);
|
|
70
|
+
for (const owner of sorted) {
|
|
71
|
+
const ownerBuf = Buffer.from(owner, 'utf-8');
|
|
72
|
+
const lenBuf = Buffer.alloc(4);
|
|
73
|
+
lenBuf.writeUInt32BE(ownerBuf.length);
|
|
74
|
+
hash.update(lenBuf);
|
|
75
|
+
hash.update(ownerBuf);
|
|
76
|
+
}
|
|
77
|
+
return `1220${hash.digest('hex')}`;
|
|
40
78
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,42 +1,18 @@
|
|
|
1
1
|
export * from './address';
|
|
2
2
|
export * from './amulet';
|
|
3
3
|
export * from './auth';
|
|
4
|
+
export * from './client';
|
|
4
5
|
export * from './crypto';
|
|
5
6
|
export * from './daml-serde';
|
|
6
7
|
export * from './deferredValue';
|
|
8
|
+
export * from './errors';
|
|
7
9
|
export * from './events';
|
|
10
|
+
export * from './minFee';
|
|
8
11
|
export * from './provider';
|
|
9
12
|
export * from './refresh';
|
|
13
|
+
export * from './sdk/index';
|
|
10
14
|
export * from './transaction';
|
|
11
|
-
|
|
12
|
-
// Core types
|
|
13
|
-
export {
|
|
14
|
-
buildTemplateId,
|
|
15
|
-
CommandStatus,
|
|
16
|
-
type Contract,
|
|
17
|
-
type ExternalSignature,
|
|
18
|
-
type IntLike,
|
|
19
|
-
IntLikeSchema,
|
|
20
|
-
type PreparedTransaction,
|
|
21
|
-
type SubmitActors,
|
|
22
|
-
type SubmitResult,
|
|
23
|
-
type TemplateId,
|
|
24
|
-
type UserRight,
|
|
25
|
-
type UserRightKind,
|
|
26
|
-
type WaitAccepted,
|
|
27
|
-
type WaitOptions,
|
|
28
|
-
type WaitRejected,
|
|
29
|
-
type WaitResult,
|
|
30
|
-
} from './types';
|
|
31
|
-
|
|
32
|
-
// Errors
|
|
33
|
-
export { CantonError, CantonProtocolError, CantonTransportError } from './errors';
|
|
34
|
-
|
|
35
|
-
// Canton Client (low-level transport)
|
|
36
|
-
export * from './client';
|
|
37
|
-
|
|
38
|
-
// Canton SDK (high-level API)
|
|
39
|
-
export { CantonSdk, type NormalizedActiveContract } from './sdk/index';
|
|
15
|
+
export * from './types';
|
|
40
16
|
|
|
41
17
|
// Re-export only the types needed for SDK usage
|
|
42
18
|
export type {
|
package/src/minFee.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
import { canonicalizeDamlDecimal } from './types';
|
|
4
|
+
|
|
5
|
+
const minFeeArgSchema = z.object({ minFee: z.string() });
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extract and canonicalize the `minFee` Daml Decimal from an IMinFee contract's
|
|
9
|
+
* `createArgument`. Throws a ZodError if the shape doesn't match.
|
|
10
|
+
*/
|
|
11
|
+
export const parseMinFeeValue = (createArgument: unknown): string =>
|
|
12
|
+
canonicalizeDamlDecimal(minFeeArgSchema.parse(createArgument).minFee);
|