@europeum-ebsi/cli 0.0.0 → 1.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +289 -289
- package/LICENSES.txt +538 -0
- package/README.md +1140 -98
- package/dist/api/client.d.ts +4 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +14 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/fetch.d.ts +13 -0
- package/dist/api/fetch.d.ts.map +1 -0
- package/dist/api/fetch.js +30 -0
- package/dist/api/fetch.js.map +1 -0
- package/dist/api/params.d.ts +4 -0
- package/dist/api/params.d.ts.map +1 -0
- package/dist/api/params.js +9 -0
- package/dist/api/params.js.map +1 -0
- package/dist/auth/dcql.d.ts +5 -0
- package/dist/auth/dcql.d.ts.map +1 -0
- package/dist/auth/dcql.js +41 -0
- package/dist/auth/dcql.js.map +1 -0
- package/dist/auth/presentation.d.ts +30 -0
- package/dist/auth/presentation.d.ts.map +1 -0
- package/dist/auth/presentation.js +99 -0
- package/dist/auth/presentation.js.map +1 -0
- package/dist/auth/token.d.ts +11 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/auth/token.js +116 -0
- package/dist/auth/token.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +96 -10
- package/dist/cli.js.map +1 -1
- package/dist/commands/auth.d.ts +3 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +99 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/config-cmd.d.ts +3 -0
- package/dist/commands/config-cmd.d.ts.map +1 -0
- package/dist/commands/config-cmd.js +86 -0
- package/dist/commands/config-cmd.js.map +1 -0
- package/dist/commands/contracts-registry.d.ts +3 -0
- package/dist/commands/contracts-registry.d.ts.map +1 -0
- package/dist/commands/contracts-registry.js +132 -0
- package/dist/commands/contracts-registry.js.map +1 -0
- package/dist/commands/did-registry.d.ts +3 -0
- package/dist/commands/did-registry.d.ts.map +1 -0
- package/dist/commands/did-registry.js +110 -0
- package/dist/commands/did-registry.js.map +1 -0
- package/dist/commands/faucet.d.ts +3 -0
- package/dist/commands/faucet.d.ts.map +1 -0
- package/dist/commands/faucet.js +78 -0
- package/dist/commands/faucet.js.map +1 -0
- package/dist/commands/health.d.ts +3 -0
- package/dist/commands/health.d.ts.map +1 -0
- package/dist/commands/health.js +20 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/issuers-registry.d.ts +3 -0
- package/dist/commands/issuers-registry.d.ts.map +1 -0
- package/dist/commands/issuers-registry.js +340 -0
- package/dist/commands/issuers-registry.js.map +1 -0
- package/dist/commands/ledger.d.ts +3 -0
- package/dist/commands/ledger.d.ts.map +1 -0
- package/dist/commands/ledger.js +549 -372
- package/dist/commands/ledger.js.map +1 -1
- package/dist/commands/onboarding.d.ts +3 -0
- package/dist/commands/onboarding.d.ts.map +1 -0
- package/dist/commands/onboarding.js +301 -0
- package/dist/commands/onboarding.js.map +1 -0
- package/dist/commands/openapi.d.ts +3 -0
- package/dist/commands/openapi.d.ts.map +1 -0
- package/dist/commands/openapi.js +37 -0
- package/dist/commands/openapi.js.map +1 -0
- package/dist/commands/policies-registry.d.ts +3 -0
- package/dist/commands/policies-registry.d.ts.map +1 -0
- package/dist/commands/policies-registry.js +198 -0
- package/dist/commands/policies-registry.js.map +1 -0
- package/dist/commands/registry.d.ts +27 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +62 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/schemas-registry.d.ts +3 -0
- package/dist/commands/schemas-registry.d.ts.map +1 -0
- package/dist/commands/schemas-registry.js +231 -0
- package/dist/commands/schemas-registry.js.map +1 -0
- package/dist/commands/shared/args.d.ts +2 -0
- package/dist/commands/shared/args.d.ts.map +1 -0
- package/dist/commands/shared/args.js +4 -0
- package/dist/commands/shared/args.js.map +1 -0
- package/dist/commands/shared/wallet-opts.d.ts +9 -0
- package/dist/commands/shared/wallet-opts.d.ts.map +1 -0
- package/dist/commands/shared/wallet-opts.js +44 -0
- package/dist/commands/shared/wallet-opts.js.map +1 -0
- package/dist/commands/timestamp.d.ts +3 -0
- package/dist/commands/timestamp.d.ts.map +1 -0
- package/dist/commands/timestamp.js +250 -0
- package/dist/commands/timestamp.js.map +1 -0
- package/dist/commands/track-and-trace.d.ts +3 -0
- package/dist/commands/track-and-trace.d.ts.map +1 -0
- package/dist/commands/track-and-trace.js +235 -0
- package/dist/commands/track-and-trace.js.map +1 -0
- package/dist/commands/wallet.d.ts +3 -0
- package/dist/commands/wallet.d.ts.map +1 -0
- package/dist/commands/wallet.js +123 -0
- package/dist/commands/wallet.js.map +1 -0
- package/dist/config/config.d.ts +45 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +111 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/ebsi-env.d.ts +4 -0
- package/dist/config/ebsi-env.d.ts.map +1 -0
- package/dist/config/ebsi-env.js +37 -0
- package/dist/config/ebsi-env.js.map +1 -0
- package/dist/crypto/wallet.d.ts +34 -0
- package/dist/crypto/wallet.d.ts.map +1 -0
- package/dist/crypto/wallet.js +100 -0
- package/dist/crypto/wallet.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -6
- package/dist/index.js.map +1 -1
- package/dist/ledger/read.d.ts +11 -0
- package/dist/ledger/read.d.ts.map +1 -0
- package/dist/ledger/read.js +24 -0
- package/dist/ledger/read.js.map +1 -0
- package/dist/ledger/registries.d.ts +25 -0
- package/dist/ledger/registries.d.ts.map +1 -0
- package/dist/ledger/registries.js +111 -0
- package/dist/ledger/registries.js.map +1 -0
- package/dist/ledger/write.d.ts +43 -0
- package/dist/ledger/write.d.ts.map +1 -0
- package/dist/ledger/write.js +119 -0
- package/dist/ledger/write.js.map +1 -0
- package/dist/onboarding/vc.d.ts +18 -0
- package/dist/onboarding/vc.d.ts.map +1 -0
- package/dist/onboarding/vc.js +72 -0
- package/dist/onboarding/vc.js.map +1 -0
- package/dist/output/format.d.ts +7 -0
- package/dist/output/format.d.ts.map +1 -0
- package/dist/output/format.js +94 -0
- package/dist/output/format.js.map +1 -0
- package/dist/tui/App.d.ts +3 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +99 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/CommandPalette.d.ts +8 -0
- package/dist/tui/CommandPalette.d.ts.map +1 -0
- package/dist/tui/CommandPalette.js +105 -0
- package/dist/tui/CommandPalette.js.map +1 -0
- package/package.json +66 -108
- package/src/api/client.ts +26 -0
- package/src/api/fetch.ts +53 -0
- package/src/api/params.ts +17 -0
- package/src/auth/dcql.ts +84 -0
- package/src/auth/presentation.ts +255 -0
- package/src/auth/token.ts +244 -0
- package/src/cli.ts +164 -0
- package/src/commands/auth.ts +119 -0
- package/src/commands/config-cmd.ts +122 -0
- package/src/commands/contracts-registry.ts +156 -0
- package/src/commands/did-registry.ts +126 -0
- package/src/commands/faucet.ts +112 -0
- package/src/commands/health.ts +21 -0
- package/src/commands/issuers-registry.ts +385 -0
- package/src/commands/ledger.ts +777 -0
- package/src/commands/onboarding.ts +411 -0
- package/src/commands/openapi.ts +42 -0
- package/src/commands/policies-registry.ts +218 -0
- package/src/commands/registry.ts +152 -0
- package/src/commands/schemas-registry.ts +255 -0
- package/src/commands/shared/args.ts +14 -0
- package/src/commands/shared/wallet-opts.ts +85 -0
- package/src/commands/timestamp.ts +272 -0
- package/src/commands/track-and-trace.ts +263 -0
- package/src/commands/wallet.ts +175 -0
- package/src/config/config.ts +275 -0
- package/src/config/ebsi-env.ts +67 -0
- package/src/crypto/wallet.ts +291 -0
- package/src/index.ts +24 -0
- package/src/ledger/read.ts +70 -0
- package/src/ledger/registries.ts +285 -0
- package/src/ledger/write.ts +381 -0
- package/src/onboarding/vc.ts +205 -0
- package/src/output/format.ts +157 -0
- package/src/tui/App.tsx +282 -0
- package/src/tui/CommandPalette.tsx +223 -0
- package/bin/cli.js +0 -13
- package/dist/abi/pilot/DidRegistry.js +0 -568
- package/dist/abi/pilot/DidRegistry.js.map +0 -1
- package/dist/abi/pilot/Ptr.js +0 -666
- package/dist/abi/pilot/Ptr.js.map +0 -1
- package/dist/abi/pilot/SchemaSCRegistry.js +0 -264
- package/dist/abi/pilot/SchemaSCRegistry.js.map +0 -1
- package/dist/abi/pilot/Tcr.js +0 -715
- package/dist/abi/pilot/Tcr.js.map +0 -1
- package/dist/abi/pilot/Timestamp.js +0 -658
- package/dist/abi/pilot/Timestamp.js.map +0 -1
- package/dist/abi/pilot/Tir.js +0 -428
- package/dist/abi/pilot/Tir.js.map +0 -1
- package/dist/abi/pilot/TnT.js +0 -842
- package/dist/abi/pilot/TnT.js.map +0 -1
- package/dist/abi/pilot/Tpr.js +0 -492
- package/dist/abi/pilot/Tpr.js.map +0 -1
- package/dist/abi/test/DidRegistry.js +0 -568
- package/dist/abi/test/DidRegistry.js.map +0 -1
- package/dist/abi/test/Ptr.js +0 -666
- package/dist/abi/test/Ptr.js.map +0 -1
- package/dist/abi/test/SchemaSCRegistry.js +0 -300
- package/dist/abi/test/SchemaSCRegistry.js.map +0 -1
- package/dist/abi/test/Tcr.js +0 -715
- package/dist/abi/test/Tcr.js.map +0 -1
- package/dist/abi/test/Timestamp.js +0 -658
- package/dist/abi/test/Timestamp.js.map +0 -1
- package/dist/abi/test/Tir.js +0 -428
- package/dist/abi/test/Tir.js.map +0 -1
- package/dist/abi/test/TnT.js +0 -842
- package/dist/abi/test/TnT.js.map +0 -1
- package/dist/abi/test/Tpr.js +0 -492
- package/dist/abi/test/Tpr.js.map +0 -1
- package/dist/app.js +0 -659
- package/dist/app.js.map +0 -1
- package/dist/buildParam/didr.js +0 -374
- package/dist/buildParam/didr.js.map +0 -1
- package/dist/buildParam/index.js +0 -53
- package/dist/buildParam/index.js.map +0 -1
- package/dist/buildParam/ptr.js +0 -80
- package/dist/buildParam/ptr.js.map +0 -1
- package/dist/buildParam/tcr.js +0 -36
- package/dist/buildParam/tcr.js.map +0 -1
- package/dist/buildParam/timestamp.js +0 -350
- package/dist/buildParam/timestamp.js.map +0 -1
- package/dist/buildParam/tir.js +0 -110
- package/dist/buildParam/tir.js.map +0 -1
- package/dist/buildParam/tnt.js +0 -214
- package/dist/buildParam/tnt.js.map +0 -1
- package/dist/buildParam/tpr.js +0 -91
- package/dist/buildParam/tpr.js.map +0 -1
- package/dist/buildParam/tsr.js +0 -115
- package/dist/buildParam/tsr.js.map +0 -1
- package/dist/commands/authorisation.js +0 -144
- package/dist/commands/authorisation.js.map +0 -1
- package/dist/commands/compute.js +0 -680
- package/dist/commands/compute.js.map +0 -1
- package/dist/commands/conformance.js +0 -813
- package/dist/commands/conformance.js.map +0 -1
- package/dist/commands/hardwarewallet.js +0 -41
- package/dist/commands/hardwarewallet.js.map +0 -1
- package/dist/commands/index.js +0 -8
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/ptr.js +0 -54
- package/dist/commands/ptr.js.map +0 -1
- package/dist/commands/tcr.js +0 -50
- package/dist/commands/tcr.js.map +0 -1
- package/dist/commands/tir.js +0 -64
- package/dist/commands/tir.js.map +0 -1
- package/dist/commands/tnl.js +0 -81
- package/dist/commands/tnl.js.map +0 -1
- package/dist/commands/tsr.js +0 -45
- package/dist/commands/tsr.js.map +0 -1
- package/dist/commands/view.js +0 -53
- package/dist/commands/view.js.map +0 -1
- package/dist/config.js +0 -497
- package/dist/config.js.map +0 -1
- package/dist/interfaces/context.js +0 -2
- package/dist/interfaces/context.js.map +0 -1
- package/dist/interfaces/contracts/ProxyFactory.js +0 -2
- package/dist/interfaces/contracts/ProxyFactory.js.map +0 -1
- package/dist/interfaces/contracts/ProxyTemplateRegistry.js +0 -2
- package/dist/interfaces/contracts/ProxyTemplateRegistry.js.map +0 -1
- package/dist/interfaces/contracts/SchemaSCRegistry.js +0 -2
- package/dist/interfaces/contracts/SchemaSCRegistry.js.map +0 -1
- package/dist/interfaces/contracts/common.js +0 -2
- package/dist/interfaces/contracts/common.js.map +0 -1
- package/dist/interfaces/index.js +0 -5
- package/dist/interfaces/index.js.map +0 -1
- package/dist/interfaces/jsonrpc.interface.js +0 -2
- package/dist/interfaces/jsonrpc.interface.js.map +0 -1
- package/dist/interfaces/paginated-list.interface.js +0 -2
- package/dist/interfaces/paginated-list.interface.js.map +0 -1
- package/dist/interfaces/unsigned-transaction.interface.js +0 -2
- package/dist/interfaces/unsigned-transaction.interface.js.map +0 -1
- package/dist/interfaces/utils.interface.js +0 -2
- package/dist/interfaces/utils.interface.js.map +0 -1
- package/dist/programs/migrateDid.js +0 -159
- package/dist/programs/migrateDid.js.map +0 -1
- package/dist/programs/migrateDids.js +0 -232
- package/dist/programs/migrateDids.js.map +0 -1
- package/dist/programs/migrateTsr.js +0 -201
- package/dist/programs/migrateTsr.js.map +0 -1
- package/dist/scripts/accreditAndAuthorize/conformance/step1 +0 -34
- package/dist/scripts/accreditAndAuthorize/conformance/step2 +0 -18
- package/dist/scripts/accreditAndAuthorize/conformance/step3 +0 -9
- package/dist/scripts/accreditAndAuthorize/conformance/step4 +0 -27
- package/dist/scripts/accreditAndAuthorize/conformance/step5 +0 -13
- package/dist/scripts/accreditAndAuthorize/conformance/step6 +0 -14
- package/dist/scripts/accreditAndAuthorize/conformance/step7 +0 -7
- package/dist/scripts/accreditAndAuthorize/test/step1 +0 -34
- package/dist/scripts/accreditAndAuthorize/test/step2 +0 -18
- package/dist/scripts/accreditAndAuthorize/test/step3 +0 -9
- package/dist/scripts/accreditAndAuthorize/test/step4 +0 -27
- package/dist/scripts/accreditAndAuthorize/test/step5 +0 -13
- package/dist/scripts/accreditAndAuthorize/test/step6 +0 -14
- package/dist/scripts/accreditAndAuthorize/test/step7 +0 -7
- package/dist/scripts/accreditTI +0 -21
- package/dist/scripts/assets/Nodes.json +0 -27
- package/dist/scripts/assets/vcdm1.1/CTRevocableCredential.json +0 -30
- package/dist/scripts/assets/vcdm1.1/CredentialToAttestVerifiableAuthorisationForTrustChain.json +0 -29
- package/dist/scripts/assets/vcdm1.1/Nodes.json +0 -27
- package/dist/scripts/assets/vcdm1.1/TrustedNodesList.json +0 -35
- package/dist/scripts/assets/vcdm1.1/VerifiableAccreditationToAccredit.json +0 -35
- package/dist/scripts/assets/vcdm1.1/VerifiableAccreditationToAttest.json +0 -33
- package/dist/scripts/assets/vcdm1.1/VerifiableAuthorisationForTrustChain.json +0 -22
- package/dist/scripts/assets/vcdm1.1/VerifiableAuthorisationToInvoke.json +0 -24
- package/dist/scripts/assets/vcdm1.1/VerifiableAuthorisationToOnboard.json +0 -24
- package/dist/scripts/assets/vcdm2.0/CredentialToAttestVerifiableAuthorisationForTrustChain.json +0 -29
- package/dist/scripts/assets/vcdm2.0/TrustedNodesList.json +0 -36
- package/dist/scripts/assets/vcdm2.0/VerifiableAccreditationToAccredit.json +0 -40
- package/dist/scripts/assets/vcdm2.0/VerifiableAccreditationToAttest.json +0 -38
- package/dist/scripts/assets/vcdm2.0/VerifiableAuthorisationForTrustChain.json +0 -30
- package/dist/scripts/assets/vcdm2.0/VerifiableAuthorisationToInvoke.json +0 -24
- package/dist/scripts/assets/vcdm2.0/VerifiableAuthorisationToOnboard.json +0 -23
- package/dist/scripts/bootstrap/0a-loadTPROperator +0 -5
- package/dist/scripts/bootstrap/0b-loadAdmin +0 -8
- package/dist/scripts/bootstrap/1-populateTPR +0 -92
- package/dist/scripts/bootstrap/2-populateDID +0 -6
- package/dist/scripts/bootstrap/3-populateTimestamp +0 -9
- package/dist/scripts/bootstrap/4-populateTIR +0 -8
- package/dist/scripts/bootstrap/5-populateTSR +0 -85
- package/dist/scripts/bootstrap/6-setupConformanceIssuer +0 -35
- package/dist/scripts/bootstrap/README.md +0 -218
- package/dist/scripts/issueVcInvoke +0 -10
- package/dist/scripts/issueVcOnboard +0 -9
- package/dist/scripts/issueVcRootTAO +0 -11
- package/dist/scripts/issueVcTAO +0 -12
- package/dist/scripts/issueVcTI +0 -12
- package/dist/scripts/issueVcTnl +0 -32
- package/dist/scripts/issue_CTRevocableCredential +0 -12
- package/dist/scripts/issue_SelfAttestationSupportOffice +0 -10
- package/dist/scripts/issue_VerifiableAccreditationToAccredit +0 -11
- package/dist/scripts/issue_VerifiableAccreditationToAttest +0 -11
- package/dist/scripts/issue_VerifiableAuthorisationForTrustChain +0 -10
- package/dist/scripts/issue_VerifiableAuthorisationToOnboard +0 -9
- package/dist/scripts/preregisterIssuer +0 -6
- package/dist/scripts/registerDidDocument +0 -15
- package/dist/scripts/registerIssuer +0 -6
- package/dist/scripts/updateVcRootTAO +0 -10
- package/dist/scripts/updateVcTAO +0 -11
- package/dist/scripts/updateVcTI +0 -11
- package/dist/scripts/vcdm2.0/issueSelfAttestationSupportOffice +0 -10
- package/dist/scripts/vcdm2.0/issueVcInvoke +0 -12
- package/dist/scripts/vcdm2.0/issueVcOnboard +0 -11
- package/dist/scripts/vcdm2.0/issueVcRootTAO +0 -14
- package/dist/scripts/vcdm2.0/issueVcTAO +0 -15
- package/dist/scripts/vcdm2.0/issueVcTI +0 -15
- package/dist/scripts/vcdm2.0/issueVcTnl +0 -34
- package/dist/scripts/vcdm2.0/registerDidDocument +0 -15
- package/dist/scripts/vcdm2.0/updateVcRootTAO +0 -13
- package/dist/scripts/vcdm2.0/updateVcTAO +0 -14
- package/dist/scripts/vcdm2.0/updateVcTI +0 -14
- package/dist/scripts/vcdm2.0/verifyVcTnl +0 -10
- package/dist/scripts/verifyVcTnl +0 -10
- package/dist/scripts/wct/accreditAndAuthorize +0 -133
- package/dist/scripts/wct/accreditAndAuthorize2 +0 -89
- package/dist/scripts/wct/holderWallet +0 -39
- package/dist/scripts/wct/holderWallet2 +0 -39
- package/dist/scripts/wct/issueToHolder +0 -38
- package/dist/scripts/wct/issueToHolder2 +0 -38
- package/dist/scripts/wct/pda1 +0 -3
- package/dist/scripts/wct/verifier +0 -8
- package/dist/scripts/wct/verifier2 +0 -7
- package/dist/utils/Client.js +0 -155
- package/dist/utils/Client.js.map +0 -1
- package/dist/utils/HardwareWallet.js +0 -326
- package/dist/utils/HardwareWallet.js.map +0 -1
- package/dist/utils/http.js +0 -132
- package/dist/utils/http.js.map +0 -1
- package/dist/utils/index.js +0 -8
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/jsonrpc.js +0 -38
- package/dist/utils/jsonrpc.js.map +0 -1
- package/dist/utils/print.js +0 -56
- package/dist/utils/print.js.map +0 -1
- package/dist/utils/utils.js +0 -427
- package/dist/utils/utils.js.map +0 -1
- package/dist/utils/vcdm.js +0 -47
- package/dist/utils/vcdm.js.map +0 -1
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { ethers, FetchRequest } from "ethers";
|
|
2
|
+
|
|
3
|
+
import type { CliConfig } from "../config/config.ts";
|
|
4
|
+
import type { WalletDetails } from "../crypto/wallet.ts";
|
|
5
|
+
import type { RegistryEntry } from "./registries.ts";
|
|
6
|
+
|
|
7
|
+
import { printWarning } from "../output/format.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Manual gas overrides for `ledger write` / `ledger write-batch` (`--gas-limit`
|
|
11
|
+
* / `--gas-price`). When omitted, both are derived from the node:
|
|
12
|
+
* `gasLimit` via `eth_estimateGas`, fees via `eth_getFeeData` (EIP-1559 when
|
|
13
|
+
* the node supports it, legacy `gasPrice` otherwise). Setting `gasPrice`
|
|
14
|
+
* explicitly forces a legacy (type 0) transaction.
|
|
15
|
+
*/
|
|
16
|
+
export interface GasOverrides {
|
|
17
|
+
gasLimit?: bigint;
|
|
18
|
+
gasPrice?: bigint;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Gas limit used by `signWriteBatch` only, when an entry's `eth_estimateGas`
|
|
23
|
+
* fails and no `--gas-limit` override was given for the batch — e.g. an
|
|
24
|
+
* entry that only becomes valid once a prior entry in the same batch has
|
|
25
|
+
* been mined, so estimating it against current (pre-submission) chain state
|
|
26
|
+
* legitimately reverts. `writeToRegistry` (a single write, with no such
|
|
27
|
+
* batch-ordering ambiguity) surfaces an estimation failure as a real error
|
|
28
|
+
* instead of silently substituting this and submitting a transaction that
|
|
29
|
+
* may be doomed to revert on-chain.
|
|
30
|
+
*/
|
|
31
|
+
const FALLBACK_GAS_LIMIT = 0x1_00_00_00n;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Percentage headroom added on top of a node-estimated (not overridden) gas
|
|
35
|
+
* limit. `eth_estimateGas` reflects chain state at call time; by the time
|
|
36
|
+
* the signed transaction actually lands, state may have shifted enough to
|
|
37
|
+
* need more gas than that moment-in-time estimate — e.g. `write-batch`
|
|
38
|
+
* submitting several writes together where an earlier entry changes storage
|
|
39
|
+
* a later entry also touches, or simply other transactions landing first.
|
|
40
|
+
* A call that would genuinely revert is still a real error either way; this
|
|
41
|
+
* buffer only protects an estimate that succeeds but comes in slightly low.
|
|
42
|
+
*/
|
|
43
|
+
const GAS_LIMIT_BUFFER_PERCENT = 120n;
|
|
44
|
+
|
|
45
|
+
export interface SignWriteBatchOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Resolved CLI configuration (used for baseUrl)
|
|
48
|
+
*/
|
|
49
|
+
config: CliConfig;
|
|
50
|
+
/**
|
|
51
|
+
* The writes to sign, in submission order
|
|
52
|
+
*/
|
|
53
|
+
entries: BatchWriteEntry[];
|
|
54
|
+
/**
|
|
55
|
+
* Manual gas overrides shared by every entry in the batch. By default gas
|
|
56
|
+
* is estimated dynamically (see `GasOverrides`).
|
|
57
|
+
*/
|
|
58
|
+
gas?: GasOverrides;
|
|
59
|
+
/**
|
|
60
|
+
* Access token (Bearer) shared by every write in the batch
|
|
61
|
+
*/
|
|
62
|
+
token: string;
|
|
63
|
+
/**
|
|
64
|
+
* Resolved wallet — `wallet.wallet` (the ethers Wallet, always the
|
|
65
|
+
* secp256k1 key) signs the transaction
|
|
66
|
+
*/
|
|
67
|
+
wallet: WalletDetails;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface WriteOptions {
|
|
71
|
+
/**
|
|
72
|
+
* Resolved CLI configuration (used for baseUrl)
|
|
73
|
+
*/
|
|
74
|
+
config: CliConfig;
|
|
75
|
+
/**
|
|
76
|
+
* Contract address (0x-prefixed)
|
|
77
|
+
*/
|
|
78
|
+
contractAddress: string;
|
|
79
|
+
/**
|
|
80
|
+
* Parsed function arguments (from the JSON array on the CLI)
|
|
81
|
+
*/
|
|
82
|
+
functionArgs: unknown[];
|
|
83
|
+
/**
|
|
84
|
+
* Smart contract function name (e.g. "insertDidDocument")
|
|
85
|
+
*/
|
|
86
|
+
functionName: string;
|
|
87
|
+
/**
|
|
88
|
+
* Manual gas overrides. By default gas is estimated dynamically (see
|
|
89
|
+
* `GasOverrides`).
|
|
90
|
+
*/
|
|
91
|
+
gas?: GasOverrides;
|
|
92
|
+
/**
|
|
93
|
+
* Registry entry providing the ABI interface
|
|
94
|
+
*/
|
|
95
|
+
registry: RegistryEntry;
|
|
96
|
+
/**
|
|
97
|
+
* Access token (Bearer) to attach to /ledger requests
|
|
98
|
+
*/
|
|
99
|
+
token: string;
|
|
100
|
+
/**
|
|
101
|
+
* Resolved wallet — `wallet.wallet` (the ethers Wallet, always the
|
|
102
|
+
* secp256k1 key) signs the transaction
|
|
103
|
+
*/
|
|
104
|
+
wallet: WalletDetails;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface WriteReceipt {
|
|
108
|
+
blockHash: string | undefined;
|
|
109
|
+
blockNumber: number | undefined;
|
|
110
|
+
contractAddress: string;
|
|
111
|
+
from: string;
|
|
112
|
+
hash: string;
|
|
113
|
+
status: number | undefined;
|
|
114
|
+
to: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
interface BatchWriteEntry {
|
|
118
|
+
/**
|
|
119
|
+
* Parsed function arguments (from the JSON array in the batch file)
|
|
120
|
+
*/
|
|
121
|
+
functionArgs: unknown[];
|
|
122
|
+
/**
|
|
123
|
+
* Smart contract function name (e.g. "insertDidDocument")
|
|
124
|
+
*/
|
|
125
|
+
functionName: string;
|
|
126
|
+
/**
|
|
127
|
+
* Registry entry providing the ABI interface
|
|
128
|
+
*/
|
|
129
|
+
registry: RegistryEntry;
|
|
130
|
+
/**
|
|
131
|
+
* Contract address (0x-prefixed)
|
|
132
|
+
*/
|
|
133
|
+
to: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Encodes and signs a batch of registry write transactions from the same
|
|
138
|
+
* wallet, assigning each one a sequential nonce (starting from the wallet's
|
|
139
|
+
* current pending nonce) so they can be submitted together as a single
|
|
140
|
+
* JSON-RPC batch request without nonce collisions.
|
|
141
|
+
*
|
|
142
|
+
* Returns the raw signed transactions in the same order as `entries`, ready
|
|
143
|
+
* to be wrapped in `eth_sendRawTransaction` JSON-RPC requests. Does not
|
|
144
|
+
* submit anything — the caller is responsible for building and sending the
|
|
145
|
+
* batch (see `ledger write-batch`).
|
|
146
|
+
*/
|
|
147
|
+
export async function signWriteBatch(
|
|
148
|
+
opts: SignWriteBatchOptions,
|
|
149
|
+
): Promise<string[]> {
|
|
150
|
+
const { config, entries, gas, token, wallet: walletDetails } = opts;
|
|
151
|
+
|
|
152
|
+
const provider = makeLedgerProvider(config, token);
|
|
153
|
+
const connectedWallet = walletDetails.wallet.connect(provider);
|
|
154
|
+
|
|
155
|
+
// The base nonce and the fee fields are shared by every entry in the
|
|
156
|
+
// batch, so resolve each with a single RPC round-trip up front (rather
|
|
157
|
+
// than once per entry) and fan out from there.
|
|
158
|
+
const [baseNonce, feeFields] = await Promise.all([
|
|
159
|
+
connectedWallet.getNonce("pending"),
|
|
160
|
+
resolveFeeFields(provider, gas),
|
|
161
|
+
]);
|
|
162
|
+
|
|
163
|
+
// Each entry gets a precomputed, distinct nonce (baseNonce + index), so
|
|
164
|
+
// encoding + estimating + populating + signing has no cross-entry
|
|
165
|
+
// dependency and can run concurrently — only the final array order (==
|
|
166
|
+
// submission order) matters, which Promise.all preserves regardless of
|
|
167
|
+
// completion timing.
|
|
168
|
+
return Promise.all(
|
|
169
|
+
entries.map(async ({ functionArgs, functionName, registry, to }, index) => {
|
|
170
|
+
const position = `Entry #${(index + 1).toString()}`;
|
|
171
|
+
let data: string;
|
|
172
|
+
try {
|
|
173
|
+
data = registry
|
|
174
|
+
.getInterface()
|
|
175
|
+
.encodeFunctionData(functionName, functionArgs);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
178
|
+
throw new Error(
|
|
179
|
+
`${position}: failed to encode function data for "${functionName}": ${message}. ` +
|
|
180
|
+
"Check the function name and argument types.",
|
|
181
|
+
{ cause: error },
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let gasLimit: bigint;
|
|
186
|
+
try {
|
|
187
|
+
gasLimit = await resolveGasLimit(
|
|
188
|
+
provider,
|
|
189
|
+
{ data, from: walletDetails.address, to },
|
|
190
|
+
gas,
|
|
191
|
+
position,
|
|
192
|
+
);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
// Unlike `writeToRegistry`, a batch entry can legitimately fail
|
|
195
|
+
// estimation against pre-submission chain state — e.g. it only
|
|
196
|
+
// becomes valid once an earlier entry in this same batch has been
|
|
197
|
+
// mined — so fall back to a generous default instead of failing the
|
|
198
|
+
// whole batch over it.
|
|
199
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
200
|
+
printWarning(
|
|
201
|
+
`${message}; falling back to the default gas limit ${FALLBACK_GAS_LIMIT.toString()}.`,
|
|
202
|
+
);
|
|
203
|
+
gasLimit = FALLBACK_GAS_LIMIT;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const populated = await connectedWallet.populateTransaction({
|
|
207
|
+
...feeFields,
|
|
208
|
+
data,
|
|
209
|
+
gasLimit,
|
|
210
|
+
nonce: baseNonce + index,
|
|
211
|
+
to,
|
|
212
|
+
});
|
|
213
|
+
return connectedWallet.signTransaction(populated);
|
|
214
|
+
}),
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Encodes a contract function call, signs it with the wallet, and submits it
|
|
220
|
+
* through the Ledger service (`POST /ledger`) using Pattern A (see
|
|
221
|
+
* `makeLedgerProvider`).
|
|
222
|
+
*
|
|
223
|
+
* ethers automatically fills nonce and chainId. Gas is resolved dynamically
|
|
224
|
+
* against the node (fees via `getFeeData`, limit via `estimateGas`) unless
|
|
225
|
+
* overridden — see `GasOverrides`.
|
|
226
|
+
*/
|
|
227
|
+
export async function writeToRegistry(
|
|
228
|
+
opts: WriteOptions,
|
|
229
|
+
): Promise<WriteReceipt> {
|
|
230
|
+
const {
|
|
231
|
+
config,
|
|
232
|
+
contractAddress,
|
|
233
|
+
functionArgs,
|
|
234
|
+
functionName,
|
|
235
|
+
gas,
|
|
236
|
+
registry,
|
|
237
|
+
token,
|
|
238
|
+
wallet: walletDetails,
|
|
239
|
+
} = opts;
|
|
240
|
+
|
|
241
|
+
// Encode calldata
|
|
242
|
+
const iface = registry.getInterface();
|
|
243
|
+
let data: string;
|
|
244
|
+
try {
|
|
245
|
+
data = iface.encodeFunctionData(functionName, functionArgs);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
248
|
+
throw new Error(
|
|
249
|
+
`Failed to encode function data for "${functionName}": ${message}. ` +
|
|
250
|
+
"Check the function name and argument types.",
|
|
251
|
+
{ cause: error },
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const provider = makeLedgerProvider(config, token);
|
|
256
|
+
|
|
257
|
+
const [feeFields, gasLimit] = await Promise.all([
|
|
258
|
+
resolveFeeFields(provider, gas),
|
|
259
|
+
resolveGasLimit(
|
|
260
|
+
provider,
|
|
261
|
+
{ data, from: walletDetails.address, to: contractAddress },
|
|
262
|
+
gas,
|
|
263
|
+
"ledger write",
|
|
264
|
+
),
|
|
265
|
+
]);
|
|
266
|
+
|
|
267
|
+
// Connect wallet to the provider and send the transaction
|
|
268
|
+
const connectedWallet = walletDetails.wallet.connect(provider);
|
|
269
|
+
const tx = await connectedWallet.sendTransaction({
|
|
270
|
+
...feeFields,
|
|
271
|
+
data,
|
|
272
|
+
gasLimit,
|
|
273
|
+
to: contractAddress,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const receipt = await tx.wait();
|
|
277
|
+
|
|
278
|
+
// receipt?.status is typed `number | null` in ethers; coerce null to undefined
|
|
279
|
+
// so the WriteReceipt interface stays null-free (unicorn/no-null)
|
|
280
|
+
const status = receipt?.status;
|
|
281
|
+
return {
|
|
282
|
+
blockHash: receipt?.blockHash,
|
|
283
|
+
blockNumber: receipt?.blockNumber,
|
|
284
|
+
contractAddress,
|
|
285
|
+
from: walletDetails.address,
|
|
286
|
+
hash: tx.hash,
|
|
287
|
+
status: status === null ? undefined : status,
|
|
288
|
+
to: contractAddress,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Builds a JSON-RPC provider pointed at the Ledger service (`POST /ledger`)
|
|
294
|
+
* using Pattern A:
|
|
295
|
+
*
|
|
296
|
+
* FetchRequest → preflightFunc injects Bearer token → JsonRpcProvider
|
|
297
|
+
*
|
|
298
|
+
* Shared by `writeToRegistry` (single write) and `signWriteBatch` (several
|
|
299
|
+
* writes signed against one nonce sequence and submitted as a single
|
|
300
|
+
* JSON-RPC batch).
|
|
301
|
+
*/
|
|
302
|
+
function makeLedgerProvider(
|
|
303
|
+
config: CliConfig,
|
|
304
|
+
token: string,
|
|
305
|
+
): ethers.JsonRpcProvider {
|
|
306
|
+
const ledgerUrl = `${config.baseUrl}/ledger`;
|
|
307
|
+
const fetchReq = new FetchRequest(ledgerUrl);
|
|
308
|
+
// @ts-expect-error preflightFunc expects Promise<FetchRequest> in ethers types but sync return is accepted at runtime
|
|
309
|
+
fetchReq.preflightFunc = (req: FetchRequest) => {
|
|
310
|
+
req.setHeader("Authorization", `Bearer ${token}`);
|
|
311
|
+
return req;
|
|
312
|
+
};
|
|
313
|
+
return new ethers.JsonRpcProvider(fetchReq);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Resolves the fee fields for a transaction: an explicit `gas.gasPrice`
|
|
318
|
+
* override always wins, and stamps `type: 0` alongside it — otherwise, on a
|
|
319
|
+
* network that also supports EIP-1559 (like this one), ethers silently
|
|
320
|
+
* reinterprets a bare `gasPrice` as identical `maxFeePerGas`/
|
|
321
|
+
* `maxPriorityFeePerGas` values and signs a type-2 transaction instead (see
|
|
322
|
+
* `ethers`' `Signer.populateTransaction`), defeating the override. Without an
|
|
323
|
+
* override, this asks the node for its current fee data and forwards
|
|
324
|
+
* EIP-1559 fields (`maxFeePerGas`/`maxPriorityFeePerGas`) when the node
|
|
325
|
+
* supports them, falling back to a legacy `gasPrice` otherwise. Never
|
|
326
|
+
* returns both shapes — `ethers.Transaction` rejects a mix of the two.
|
|
327
|
+
*/
|
|
328
|
+
async function resolveFeeFields(
|
|
329
|
+
provider: ethers.JsonRpcProvider,
|
|
330
|
+
overrides: GasOverrides | undefined,
|
|
331
|
+
): Promise<Record<string, bigint | number>> {
|
|
332
|
+
if (overrides?.gasPrice !== undefined) {
|
|
333
|
+
return { gasPrice: overrides.gasPrice, type: 0 };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const feeData = await provider.getFeeData();
|
|
337
|
+
if (feeData.maxFeePerGas !== null && feeData.maxPriorityFeePerGas !== null) {
|
|
338
|
+
return {
|
|
339
|
+
maxFeePerGas: feeData.maxFeePerGas,
|
|
340
|
+
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
if (feeData.gasPrice !== null) {
|
|
344
|
+
return { gasPrice: feeData.gasPrice };
|
|
345
|
+
}
|
|
346
|
+
/* v8 ignore next -- defensive: every network ethers supports returns at
|
|
347
|
+
least one of the two fee shapes from getFeeData() */
|
|
348
|
+
return {};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Resolves the gas limit for a transaction: an explicit `gas.gasLimit`
|
|
353
|
+
* override always wins and is used exactly as given (no buffer). Otherwise
|
|
354
|
+
* asks the node to estimate it via `eth_estimateGas` and adds
|
|
355
|
+
* `GAS_LIMIT_BUFFER_PERCENT` headroom. A genuine estimation failure (e.g. a
|
|
356
|
+
* call that would revert) propagates as a descriptive error — this function
|
|
357
|
+
* never silently substitutes a fallback limit; `signWriteBatch`, which has a
|
|
358
|
+
* legitimate reason an entry's estimation can fail transiently, decides for
|
|
359
|
+
* itself whether to fall back (see `FALLBACK_GAS_LIMIT`).
|
|
360
|
+
*/
|
|
361
|
+
async function resolveGasLimit(
|
|
362
|
+
provider: ethers.JsonRpcProvider,
|
|
363
|
+
tx: { data: string; from: string; to: string },
|
|
364
|
+
overrides: GasOverrides | undefined,
|
|
365
|
+
label: string,
|
|
366
|
+
): Promise<bigint> {
|
|
367
|
+
if (overrides?.gasLimit !== undefined) {
|
|
368
|
+
return overrides.gasLimit;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
try {
|
|
372
|
+
const estimated = await provider.estimateGas(tx);
|
|
373
|
+
return (estimated * GAS_LIMIT_BUFFER_PERCENT) / 100n;
|
|
374
|
+
} catch (error) {
|
|
375
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
376
|
+
throw new Error(
|
|
377
|
+
`${label}: gas estimation failed (${message}). Provide --gas-limit to override.`,
|
|
378
|
+
{ cause: error },
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type { EbsiIssuer } from "@europeum-ebsi/verifiable-credential";
|
|
2
|
+
import type { Schemas } from "@europeum-ebsi/verifiable-credential/vcdm11.js";
|
|
3
|
+
|
|
4
|
+
import { fromUrl } from "@europeum-ebsi/ebsi-uri";
|
|
5
|
+
import { metadata as attestationSchema } from "@europeum-ebsi/vcdm1.1-attestation-schema";
|
|
6
|
+
import { createVerifiableCredentialJwt } from "@europeum-ebsi/verifiable-credential/vcdm11.js";
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
|
+
|
|
9
|
+
import type { CliConfig } from "../config/config.ts";
|
|
10
|
+
|
|
11
|
+
import { buildEbsiEnvConfig } from "../config/ebsi-env.ts";
|
|
12
|
+
import { deriveEs256Issuer, deriveWallet } from "../crypto/wallet.ts";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The services whose resources this credential's ids can name. Narrower than
|
|
16
|
+
* `buildEbsiEnvConfig`'s list on purpose -- `credentialSchema.id` and
|
|
17
|
+
* `termsOfUse.id` only ever point at a schema or an issuer's accreditation.
|
|
18
|
+
*/
|
|
19
|
+
const EBSI_URI_SERVICES = [
|
|
20
|
+
"did-registry",
|
|
21
|
+
"issuers-registry",
|
|
22
|
+
"schemas-registry",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export interface BuildOnboardingVcOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Resolved CLI config. Supplies the API base URL the VC's resource
|
|
28
|
+
* references are derived from (`credentialSchema`, `termsOfUse` -- already
|
|
29
|
+
* including the `/v1` prefix) and, via `buildEbsiEnvConfig`, the EBSI
|
|
30
|
+
* network they are named against. Neither reference keeps the host: both
|
|
31
|
+
* are rewritten to EBSI URIs by `toEbsiUri`.
|
|
32
|
+
*/
|
|
33
|
+
config: CliConfig;
|
|
34
|
+
holderDid: string;
|
|
35
|
+
holderThumbprint: string;
|
|
36
|
+
/**
|
|
37
|
+
* The RTAO's Issuers Registry attribute id carrying its RootTAO
|
|
38
|
+
* self-attestation — see `ebsi issuers-registry issuers attributes list
|
|
39
|
+
* <rtaoDid>`. Accepted with or without a `0x`/`0h` prefix; the credential
|
|
40
|
+
* always names it in the registry's canonical unprefixed form.
|
|
41
|
+
*/
|
|
42
|
+
rtaoAttributeId: string;
|
|
43
|
+
rtaoDid: string;
|
|
44
|
+
/**
|
|
45
|
+
* The RTAO's secp256k1 private key, used to sign the VC ES256K when no
|
|
46
|
+
* ES256 key is given.
|
|
47
|
+
*/
|
|
48
|
+
rtaoEs256kPrivateKey?: string;
|
|
49
|
+
/**
|
|
50
|
+
* The RTAO's P-256 private key. When provided the VC is signed ES256 and
|
|
51
|
+
* `rtaoEs256kPrivateKey` is not used for signing at all. Required against a
|
|
52
|
+
* deployment whose Authorisation service restricts the `did-registry:invite`
|
|
53
|
+
* credential format to ES256 -- ES256K is accepted only where every scope
|
|
54
|
+
* shares `SUPPORTED_ALGS` (`["ES256", "ES256K"]`).
|
|
55
|
+
*/
|
|
56
|
+
rtaoEs256PrivateKey?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface BuildOnboardingVcResult {
|
|
60
|
+
// Algorithm the VC was signed with, so callers can report the key used.
|
|
61
|
+
alg: EbsiIssuer["alg"];
|
|
62
|
+
rtaoKid: string;
|
|
63
|
+
vcJwt: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Signs a "VerifiableAuthorisationToOnboard" VC for `holderDid`/`holderThumbprint`,
|
|
68
|
+
* issued by the given RTAO. Mirrors `buildVerifiableAuthorisationToOnboard` in
|
|
69
|
+
* `api/tests/utils/access-tokens.ts` (the only other place in the repo that
|
|
70
|
+
* builds this VC type), but as a reusable, non-test-only function.
|
|
71
|
+
*
|
|
72
|
+
* The RTAO must already be registered on chain as `RootTAO` (e.g. via
|
|
73
|
+
* `hardhat bootstrap` or `contracts/deploy-toolkit/scripts/tests/setup-rtao.ts`)
|
|
74
|
+
* for the resulting VC to pass the Authorisation service's trust-chain check.
|
|
75
|
+
*
|
|
76
|
+
* @throws If neither `rtaoEs256PrivateKey` nor `rtaoEs256kPrivateKey` is set.
|
|
77
|
+
*/
|
|
78
|
+
export async function buildOnboardingVc(
|
|
79
|
+
opts: BuildOnboardingVcOptions,
|
|
80
|
+
): Promise<BuildOnboardingVcResult> {
|
|
81
|
+
const {
|
|
82
|
+
config,
|
|
83
|
+
holderDid,
|
|
84
|
+
holderThumbprint,
|
|
85
|
+
rtaoAttributeId,
|
|
86
|
+
rtaoDid,
|
|
87
|
+
rtaoEs256kPrivateKey,
|
|
88
|
+
rtaoEs256PrivateKey,
|
|
89
|
+
} = opts;
|
|
90
|
+
const issuer = await resolveIssuer(
|
|
91
|
+
rtaoDid,
|
|
92
|
+
rtaoEs256PrivateKey,
|
|
93
|
+
rtaoEs256kPrivateKey,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// `config.baseUrl` already carries the API version prefix (e.g.
|
|
97
|
+
// "https://api-pilot.ebsi.eu/v1"), so resource references are built from it
|
|
98
|
+
// directly rather than from the bare origin plus a hardcoded "/v1".
|
|
99
|
+
const apiBaseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
100
|
+
const ebsiEnvConfig = buildEbsiEnvConfig(config);
|
|
101
|
+
const { name: network } = ebsiEnvConfig.network;
|
|
102
|
+
|
|
103
|
+
// The Issuers Registry returns attribute ids unprefixed, and that's their
|
|
104
|
+
// canonical form in a resource path, so strip any "0x"/"0h" the caller
|
|
105
|
+
// passed -- the URI must name the attribute identically however the id was
|
|
106
|
+
// supplied, or two credentials naming the same attribute won't compare equal.
|
|
107
|
+
const attributeId = rtaoAttributeId.replace(/^0[hx]/, "");
|
|
108
|
+
|
|
109
|
+
const issuanceDate = new Date(Date.now() - 5000);
|
|
110
|
+
const expirationDate = new Date(issuanceDate.getTime() + 2 * 60 * 60 * 1000);
|
|
111
|
+
const iso = (date: Date) => `${date.toISOString().slice(0, -5)}Z`;
|
|
112
|
+
|
|
113
|
+
const vcPayload: Schemas["Attestation"] = {
|
|
114
|
+
"@context": ["https://www.w3.org/2018/credentials/v1"],
|
|
115
|
+
credentialSchema: {
|
|
116
|
+
id: toEbsiUri(
|
|
117
|
+
`${apiBaseUrl}/schemas-registry/schemas/${attestationSchema.id.base16}`,
|
|
118
|
+
network,
|
|
119
|
+
),
|
|
120
|
+
type: "FullJsonSchemaValidator2021",
|
|
121
|
+
},
|
|
122
|
+
credentialSubject: {
|
|
123
|
+
id: holderDid,
|
|
124
|
+
jwkThumbprint: holderThumbprint,
|
|
125
|
+
type: "same-device",
|
|
126
|
+
},
|
|
127
|
+
expirationDate: iso(expirationDate),
|
|
128
|
+
id: `urn:uuid:${randomUUID()}`,
|
|
129
|
+
issuanceDate: iso(issuanceDate),
|
|
130
|
+
issued: iso(issuanceDate),
|
|
131
|
+
issuer: rtaoDid,
|
|
132
|
+
termsOfUse: {
|
|
133
|
+
id: toEbsiUri(
|
|
134
|
+
`${apiBaseUrl}/issuers-registry/issuers/${rtaoDid}/attributes/${attributeId}`,
|
|
135
|
+
network,
|
|
136
|
+
),
|
|
137
|
+
type: "IssuanceCertificate",
|
|
138
|
+
},
|
|
139
|
+
type: [
|
|
140
|
+
"VerifiableCredential",
|
|
141
|
+
"VerifiableAttestation",
|
|
142
|
+
"VerifiableAuthorisationToOnboard",
|
|
143
|
+
],
|
|
144
|
+
validFrom: iso(issuanceDate),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const vcJwt = await createVerifiableCredentialJwt(
|
|
148
|
+
vcPayload,
|
|
149
|
+
issuer,
|
|
150
|
+
ebsiEnvConfig,
|
|
151
|
+
{ skipValidation: true },
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
return { alg: issuer.alg, rtaoKid: issuer.kid, vcJwt };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Picks the signing identity: the RTAO's ES256 key when it has one, otherwise
|
|
159
|
+
* the ES256K ledger key `deriveWallet` doubles up as a JWT signer. Preferring
|
|
160
|
+
* ES256 is deliberate -- every deployment that accepts ES256K for this
|
|
161
|
+
* credential also accepts ES256, but not the reverse.
|
|
162
|
+
*/
|
|
163
|
+
async function resolveIssuer(
|
|
164
|
+
rtaoDid: string,
|
|
165
|
+
rtaoEs256PrivateKey: string | undefined,
|
|
166
|
+
rtaoES256kPrivateKey: string | undefined,
|
|
167
|
+
): Promise<EbsiIssuer> {
|
|
168
|
+
if (rtaoEs256PrivateKey) {
|
|
169
|
+
return deriveEs256Issuer(rtaoEs256PrivateKey, rtaoDid);
|
|
170
|
+
}
|
|
171
|
+
if (!rtaoES256kPrivateKey) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
"No RTAO signing key. Provide --rtao-es256-key <hex> (P-256, signs " +
|
|
174
|
+
"ES256) or --rtao-es256k-key <hex> (secp256k1, signs ES256K), or set " +
|
|
175
|
+
"EBSI_RTAO_ES256_PRIVATE_KEY / EBSI_RTAO_ES256K_PRIVATE_KEY.",
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
const wallet = await deriveWallet(
|
|
179
|
+
{ es256kPrivateKey: rtaoES256kPrivateKey },
|
|
180
|
+
rtaoDid,
|
|
181
|
+
);
|
|
182
|
+
return wallet.es256k.issuer;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Turns a core-services URL into the EBSI URI it names
|
|
187
|
+
* (`ebsi:<network>:<service>:<resource>`), so ids embedded in a VC
|
|
188
|
+
* (`credentialSchema.id`, `termsOfUse.id`, ...) name a resource on the EBSI
|
|
189
|
+
* network rather than binding to whichever node happened to serve this
|
|
190
|
+
* command's requests -- a node that may later be dropped from the trust
|
|
191
|
+
* chain, invalidating every credential that pointed at it directly.
|
|
192
|
+
*
|
|
193
|
+
* `hosts` is taken from the URL itself rather than from `buildEbsiEnvConfig`:
|
|
194
|
+
* `parseUrl` matches `config.hosts` against the URL's `host`, which carries
|
|
195
|
+
* the port, while the shared env config holds the bare `hostname` -- so a
|
|
196
|
+
* local `localhost:3000` base URL would otherwise be rejected outright.
|
|
197
|
+
*/
|
|
198
|
+
function toEbsiUri(url: string, network: string): string {
|
|
199
|
+
return fromUrl(url, {
|
|
200
|
+
hosts: [new URL(url).host],
|
|
201
|
+
network: { name: network },
|
|
202
|
+
scheme: "ebsi",
|
|
203
|
+
services: EBSI_URI_SERVICES,
|
|
204
|
+
});
|
|
205
|
+
}
|