@midnight-ntwrk/midnight-did-api 0.5.0-rc1
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 +201 -0
- package/README.md +218 -0
- package/dist/api-logger.d.ts +3 -0
- package/dist/api-logger.js +8 -0
- package/dist/api-logger.js.map +1 -0
- package/dist/browser.d.ts +6 -0
- package/dist/browser.js +6 -0
- package/dist/browser.js.map +1 -0
- package/dist/config-profiles.d.ts +75 -0
- package/dist/config-profiles.js +75 -0
- package/dist/config-profiles.js.map +1 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.js +50 -0
- package/dist/config.js.map +1 -0
- package/dist/contract-instance.d.ts +7 -0
- package/dist/contract-instance.js +6 -0
- package/dist/contract-instance.js.map +1 -0
- package/dist/contract-lifecycle-operations.d.ts +4 -0
- package/dist/contract-lifecycle-operations.js +40 -0
- package/dist/contract-lifecycle-operations.js.map +1 -0
- package/dist/contract-lifecycle.d.ts +6 -0
- package/dist/contract-lifecycle.js +7 -0
- package/dist/contract-lifecycle.js.map +1 -0
- package/dist/controller-operations.d.ts +9 -0
- package/dist/controller-operations.js +49 -0
- package/dist/controller-operations.js.map +1 -0
- package/dist/deploy.d.ts +6 -0
- package/dist/deploy.js +7 -0
- package/dist/deploy.js.map +1 -0
- package/dist/did-operations.d.ts +6 -0
- package/dist/did-operations.js +7 -0
- package/dist/did-operations.js.map +1 -0
- package/dist/did-subject.d.ts +6 -0
- package/dist/did-subject.js +11 -0
- package/dist/did-subject.js.map +1 -0
- package/dist/document-operations.d.ts +5 -0
- package/dist/document-operations.js +17 -0
- package/dist/document-operations.js.map +1 -0
- package/dist/domain-to-runtime.d.ts +4 -0
- package/dist/domain-to-runtime.js +7 -0
- package/dist/domain-to-runtime.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger-mappers.d.ts +15 -0
- package/dist/ledger-mappers.js +137 -0
- package/dist/ledger-mappers.js.map +1 -0
- package/dist/ledger-state.d.ts +6 -0
- package/dist/ledger-state.js +24 -0
- package/dist/ledger-state.js.map +1 -0
- package/dist/lib.d.ts +15 -0
- package/dist/lib.js +16 -0
- package/dist/lib.js.map +1 -0
- package/dist/lightweight.d.ts +1 -0
- package/dist/lightweight.js +9 -0
- package/dist/lightweight.js.map +1 -0
- package/dist/logger-utils.d.ts +3 -0
- package/dist/logger-utils.js +26 -0
- package/dist/logger-utils.js.map +1 -0
- package/dist/network-mapping.d.ts +6 -0
- package/dist/network-mapping.js +20 -0
- package/dist/network-mapping.js.map +1 -0
- package/dist/package-paths.d.ts +10 -0
- package/dist/package-paths.js +31 -0
- package/dist/package-paths.js.map +1 -0
- package/dist/polyfills.d.ts +1 -0
- package/dist/polyfills.js +7 -0
- package/dist/polyfills.js.map +1 -0
- package/dist/private-state-storage.d.ts +8 -0
- package/dist/private-state-storage.js +18 -0
- package/dist/private-state-storage.js.map +1 -0
- package/dist/private-state.d.ts +13 -0
- package/dist/private-state.js +75 -0
- package/dist/private-state.js.map +1 -0
- package/dist/providers.d.ts +13 -0
- package/dist/providers.js +32 -0
- package/dist/providers.js.map +1 -0
- package/dist/release-artifacts.d.ts +41 -0
- package/dist/release-artifacts.js +60 -0
- package/dist/release-artifacts.js.map +1 -0
- package/dist/resolution.d.ts +15 -0
- package/dist/resolution.js +46 -0
- package/dist/resolution.js.map +1 -0
- package/dist/runtime-to-domain.d.ts +4 -0
- package/dist/runtime-to-domain.js +7 -0
- package/dist/runtime-to-domain.js.map +1 -0
- package/dist/seed.d.ts +1 -0
- package/dist/seed.js +13 -0
- package/dist/seed.js.map +1 -0
- package/dist/service-operations.d.ts +6 -0
- package/dist/service-operations.js +17 -0
- package/dist/service-operations.js.map +1 -0
- package/dist/transaction-intents.d.ts +9 -0
- package/dist/transaction-intents.js +27 -0
- package/dist/transaction-intents.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/update.d.ts +7 -0
- package/dist/update.js +8 -0
- package/dist/update.js.map +1 -0
- package/dist/verification-method-operations.d.ts +19 -0
- package/dist/verification-method-operations.js +60 -0
- package/dist/verification-method-operations.js.map +1 -0
- package/dist/verification-method-relations.d.ts +13 -0
- package/dist/verification-method-relations.js +40 -0
- package/dist/verification-method-relations.js.map +1 -0
- package/dist/wallet-context.d.ts +3 -0
- package/dist/wallet-context.js +55 -0
- package/dist/wallet-context.js.map +1 -0
- package/dist/wallet-dust.d.ts +10 -0
- package/dist/wallet-dust.js +28 -0
- package/dist/wallet-dust.js.map +1 -0
- package/dist/wallet-keys.d.ts +5 -0
- package/dist/wallet-keys.js +27 -0
- package/dist/wallet-keys.js.map +1 -0
- package/dist/wallet-provider.d.ts +3 -0
- package/dist/wallet-provider.js +29 -0
- package/dist/wallet-provider.js.map +1 -0
- package/dist/wallet-sdk-config.d.ts +32 -0
- package/dist/wallet-sdk-config.js +23 -0
- package/dist/wallet-sdk-config.js.map +1 -0
- package/dist/wallet-state.d.ts +6 -0
- package/dist/wallet-state.js +32 -0
- package/dist/wallet-state.js.map +1 -0
- package/dist/wallet.d.ts +9 -0
- package/dist/wallet.js +17 -0
- package/dist/wallet.js.map +1 -0
- package/examples/README.md +60 -0
- package/examples/bootstrap-issuer-did.ts +313 -0
- package/examples/deploy-did.ts +40 -0
- package/examples/update-did.ts +84 -0
- package/package.json +88 -0
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +23 -0
package/dist/wallet.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "./polyfills.js";
|
|
2
|
+
import { toHex } from "@midnight-ntwrk/midnight-js-utils";
|
|
3
|
+
import { randomBytes } from "./lightweight.js";
|
|
4
|
+
import { createWalletContext } from "./wallet-context.js";
|
|
5
|
+
import { waitForWalletFunds, waitForWalletSync } from "./wallet-state.js";
|
|
6
|
+
export { registerForDustGeneration } from "./wallet-dust.js";
|
|
7
|
+
export { getWalletBalances, serializeWalletState, waitForWalletFunds, waitForWalletSync, } from "./wallet-state.js";
|
|
8
|
+
export const buildWallet = async (config, seed, snapshot) => await createWalletContext(config, seed, snapshot);
|
|
9
|
+
export const restoreWalletFromState = async (config, seed, snapshot) => await createWalletContext(config, seed, snapshot);
|
|
10
|
+
export const buildWalletAndWaitForFunds = async (config, seed) => {
|
|
11
|
+
const walletContext = await buildWallet(config, seed);
|
|
12
|
+
await waitForWalletSync(walletContext);
|
|
13
|
+
await waitForWalletFunds(walletContext);
|
|
14
|
+
return walletContext;
|
|
15
|
+
};
|
|
16
|
+
export const buildFreshWallet = async (config) => await buildWalletAndWaitForFunds(config, toHex(randomBytes(32)));
|
|
17
|
+
//# sourceMappingURL=wallet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,CAAC;AAExB,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC9B,MAAc,EACd,IAAY,EACZ,QAAsC,EACH,EAAE,CACrC,MAAM,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EACzC,MAAc,EACd,IAAY,EACZ,QAAqC,EACF,EAAE,CACrC,MAAM,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,0BAA0B,GAAG,KAAK,EAC7C,MAAc,EACd,IAAY,EACuB,EAAE;IACrC,MAAM,aAAa,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtD,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC;IACvC,MAAM,kBAAkB,CAAC,aAAa,CAAC,CAAC;IACxC,OAAO,aAAa,CAAC;AACvB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,MAAc,EACqB,EAAE,CACrC,MAAM,0BAA0B,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# DID API examples
|
|
2
|
+
|
|
3
|
+
These examples are package-level Node/TypeScript snippets for direct API usage.
|
|
4
|
+
They do not import resolver service, manager service, or UI code.
|
|
5
|
+
|
|
6
|
+
Run the examples from the repository root with development dependencies
|
|
7
|
+
installed; the commands use the root `ts-node` dev dependency.
|
|
8
|
+
|
|
9
|
+
## Deploy a DID
|
|
10
|
+
|
|
11
|
+
Run against a funded standalone wallet seed and local standalone network:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
MIDNIGHT_WALLET_SEED=<hex-seed> \
|
|
15
|
+
pnpm exec ts-node --esm packages/api/examples/deploy-did.ts
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The example builds a wallet, configures providers, initializes DID private state,
|
|
19
|
+
deploys the DID contract, and resolves the resulting DID document.
|
|
20
|
+
|
|
21
|
+
## Update a DID
|
|
22
|
+
|
|
23
|
+
Run after deployment with the deployed contract address:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
MIDNIGHT_WALLET_SEED=<hex-seed> \
|
|
27
|
+
MIDNIGHT_DID_CONTRACT_ADDRESS=<contract-address> \
|
|
28
|
+
pnpm exec ts-node --esm packages/api/examples/update-did.ts
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The example joins an existing DID contract, adds a verification method and
|
|
32
|
+
authentication relation, adds a DIDComm service, updates the service endpoint,
|
|
33
|
+
and resolves the final DID document.
|
|
34
|
+
|
|
35
|
+
The verification method key value in `update-did.ts` is placeholder key material
|
|
36
|
+
for a disposable standalone flow. Replace it with a real verification method key
|
|
37
|
+
before using the example against any shared or persistent network.
|
|
38
|
+
|
|
39
|
+
## Bootstrap an issuer DID
|
|
40
|
+
|
|
41
|
+
Run against any standalone Midnight environment to deploy an issuer DID with
|
|
42
|
+
both Ed25519 authentication and Jubjub assertionMethod verification methods,
|
|
43
|
+
emitting a JSON keystore consumable by downstream issuers:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
ISSUER_BOOTSTRAP_SEED=<hex-seed> \
|
|
47
|
+
ISSUER_KEYSTORE_OUT=./issuer-keystore.json \
|
|
48
|
+
INDEXER_URL=<indexer-url> \
|
|
49
|
+
NODE_RPC_URL=<node-rpc-url> \
|
|
50
|
+
PROOF_SERVER_URL=<proof-server-url> \
|
|
51
|
+
pnpm exec ts-node --esm packages/api/examples/bootstrap-issuer-did.ts
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The example builds a funded wallet from the genesis seed, calls
|
|
55
|
+
`createDID` → `addVerificationMethod` (Ed25519) →
|
|
56
|
+
`addVerificationMethodRelation` (authentication) →
|
|
57
|
+
`addSchnorrJubjubVerificationMethod` (Jubjub) →
|
|
58
|
+
`addVerificationMethodRelation` (assertionMethod), wraps each chain write in a
|
|
59
|
+
dust-shortage retry, and writes the resulting keystore to
|
|
60
|
+
`ISSUER_KEYSTORE_OUT`.
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
//! Bootstrap an "issuer DID" with the two verification methods
|
|
2
|
+
//! the OID4VP/VCI flows need (Ed25519 authentication + Jubjub
|
|
3
|
+
//! assertionMethod), then write a JSON keystore consumable by
|
|
4
|
+
//! `IssuerDIDIT-mock/src/services/issuerDid.ts`.
|
|
5
|
+
//!
|
|
6
|
+
//! Lives in the api package's examples/ rather than in the
|
|
7
|
+
//! IssuerDIDIT-mock or the solution-examples workspace because:
|
|
8
|
+
//!
|
|
9
|
+
//! - midnight-did packages have intricate workspace deps
|
|
10
|
+
//! (`jubjub-schnorr` etc.) that only resolve cleanly from
|
|
11
|
+
//! inside *this* workspace. The IssuerDIDIT-mock package
|
|
12
|
+
//! ships intentionally outside any workspace, so it can't pull
|
|
13
|
+
//! the api in transitively.
|
|
14
|
+
//! - The midnight-identity-solution-examples parent workspace
|
|
15
|
+
//! uses a custom `bootstrap-libs.sh`-assembled libs layout
|
|
16
|
+
//! that drops `jubjub-schnorr` entirely.
|
|
17
|
+
//!
|
|
18
|
+
//! From this workspace's root:
|
|
19
|
+
//!
|
|
20
|
+
//! ```bash
|
|
21
|
+
//! ISSUER_BOOTSTRAP_SEED=0000…0001 \
|
|
22
|
+
//! ISSUER_KEYSTORE_OUT=/abs/path/to/issuer-keystore.json \
|
|
23
|
+
//! INDEXER_URL=http://127.0.0.1:8088/api/v3/graphql \
|
|
24
|
+
//! NODE_RPC_URL=http://127.0.0.1:9944 \
|
|
25
|
+
//! PROOF_SERVER_URL=http://127.0.0.1:6300 \
|
|
26
|
+
//! pnpm exec ts-node --esm packages/api/examples/bootstrap-issuer-did.ts
|
|
27
|
+
//! ```
|
|
28
|
+
//!
|
|
29
|
+
//! ## Output keystore JSON shape
|
|
30
|
+
//!
|
|
31
|
+
//! Matches what the Rust `did-bootstrap` CLI produces, so the
|
|
32
|
+
//! existing IssuerDIDIT-mock loader keeps working unchanged:
|
|
33
|
+
//!
|
|
34
|
+
//! ```json
|
|
35
|
+
//! {
|
|
36
|
+
//! "did": "did:midnight:undeployed:...",
|
|
37
|
+
//! "ed25519": { "kid": "did:midnight:...#key-auth", "secret_hex": "..." },
|
|
38
|
+
//! "jubjub": { "kid": "did:midnight:...#key-assert", "secret_hex": "..." }
|
|
39
|
+
//! }
|
|
40
|
+
//! ```
|
|
41
|
+
//!
|
|
42
|
+
//! ## Determinism
|
|
43
|
+
//!
|
|
44
|
+
//! Wallet HD derivation comes from `@midnight-ntwrk/wallet-sdk-hd`
|
|
45
|
+
//! (the TS source of truth — Rust's wallet-core mirrors it; the
|
|
46
|
+
//! 2026-05-29 standalone bootstrap confirmed empirical parity by
|
|
47
|
+
//! pulling the genesis-mint DUST from the derived address).
|
|
48
|
+
//!
|
|
49
|
+
//! Ed25519/Jubjub DID-key secrets are 32 random bytes per
|
|
50
|
+
//! bootstrap (no determinism). Env-wipe between iterations
|
|
51
|
+
//! rotates the DID contract address anyway; deterministic key
|
|
52
|
+
//! bytes buys nothing user-visible. Match the Rust CLI's HKDF
|
|
53
|
+
//! scheme later if a future caller needs reproducible keystore
|
|
54
|
+
//! bytes across runs against the same env.
|
|
55
|
+
|
|
56
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
57
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
58
|
+
|
|
59
|
+
import {
|
|
60
|
+
createMidnightDIDString,
|
|
61
|
+
parseContractAddress,
|
|
62
|
+
} from "@midnight-ntwrk/midnight-did/midnight";
|
|
63
|
+
import {
|
|
64
|
+
addSchnorrJubjubVerificationMethod,
|
|
65
|
+
addVerificationMethod,
|
|
66
|
+
addVerificationMethodRelation,
|
|
67
|
+
buildWalletAndWaitForFunds,
|
|
68
|
+
configureProviders,
|
|
69
|
+
createDID,
|
|
70
|
+
getMidnightNetwork,
|
|
71
|
+
initPrivateState,
|
|
72
|
+
ProfileConfig,
|
|
73
|
+
registerForDustGeneration,
|
|
74
|
+
resolve,
|
|
75
|
+
} from "@midnight-ntwrk/midnight-did-api";
|
|
76
|
+
import {
|
|
77
|
+
createVerificationMethod,
|
|
78
|
+
CurveType,
|
|
79
|
+
encodeBase64Url,
|
|
80
|
+
KeyType,
|
|
81
|
+
VerificationMethodRelationType,
|
|
82
|
+
VerificationMethodType,
|
|
83
|
+
} from "@midnight-ntwrk/midnight-did-domain";
|
|
84
|
+
import { deriveJubjubPublicKeyFromSeed } from "@midnight-ntwrk/midnight-did-jubjub-schnorr";
|
|
85
|
+
import { ed25519 } from "@noble/curves/ed25519";
|
|
86
|
+
|
|
87
|
+
// ── config from env ─────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
const seedInput = process.env.ISSUER_BOOTSTRAP_SEED;
|
|
90
|
+
if (!seedInput || seedInput.length === 0) {
|
|
91
|
+
console.error("Set ISSUER_BOOTSTRAP_SEED (hex 64 chars or any short string)");
|
|
92
|
+
process.exit(2);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const outPath = process.env.ISSUER_KEYSTORE_OUT;
|
|
96
|
+
if (!outPath || outPath.length === 0) {
|
|
97
|
+
console.error("Set ISSUER_KEYSTORE_OUT to an absolute path");
|
|
98
|
+
process.exit(2);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const indexerUrl =
|
|
102
|
+
process.env.INDEXER_URL ?? "http://127.0.0.1:8088/api/v3/graphql";
|
|
103
|
+
const nodeRpcUrl = process.env.NODE_RPC_URL ?? "http://127.0.0.1:9944";
|
|
104
|
+
const proofServerUrl = process.env.PROOF_SERVER_URL ?? "http://127.0.0.1:6300";
|
|
105
|
+
|
|
106
|
+
if (existsSync(outPath)) {
|
|
107
|
+
console.error(
|
|
108
|
+
`Refusing to overwrite ${outPath}. Delete it manually to re-bootstrap.`,
|
|
109
|
+
);
|
|
110
|
+
process.exit(2);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ── helpers ──────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
const DUST_RETRY =
|
|
116
|
+
/Not enough Dust generated to pay the fee|could not balance dust/i;
|
|
117
|
+
const sleep = (ms: number): Promise<void> =>
|
|
118
|
+
new Promise((r) => setTimeout(r, ms));
|
|
119
|
+
|
|
120
|
+
async function retryOnDustShortage<T>(
|
|
121
|
+
label: string,
|
|
122
|
+
fn: () => Promise<T>,
|
|
123
|
+
retries = 3,
|
|
124
|
+
delayMs = 8_000,
|
|
125
|
+
): Promise<T> {
|
|
126
|
+
let lastErr: unknown;
|
|
127
|
+
for (let attempt = 0; attempt <= retries; attempt += 1) {
|
|
128
|
+
try {
|
|
129
|
+
return await fn();
|
|
130
|
+
} catch (err) {
|
|
131
|
+
lastErr = err;
|
|
132
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
133
|
+
if (attempt === retries || !DUST_RETRY.test(msg)) throw err;
|
|
134
|
+
console.error(
|
|
135
|
+
`[bootstrap] ${label} dust shortage on attempt ${attempt + 1}/${retries + 1}, sleeping ${delayMs}ms`,
|
|
136
|
+
);
|
|
137
|
+
await sleep(delayMs);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function randomSecret32(): Uint8Array {
|
|
144
|
+
return Uint8Array.from(randomBytes(32));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// 64 hex chars (with optional `0x`) → decoded verbatim;
|
|
148
|
+
/// anything else → SHA-256-hashed to 32 bytes. Matches the Rust
|
|
149
|
+
/// CLI's `seed_to_bytes` normalisation exactly so the same
|
|
150
|
+
/// `ISSUER_BOOTSTRAP_SEED` value produces the same wallet seed
|
|
151
|
+
/// across both bootstrap paths.
|
|
152
|
+
function seedToHexString(seed: string): string {
|
|
153
|
+
const stripped = seed.startsWith("0x") ? seed.slice(2) : seed;
|
|
154
|
+
if (stripped.length === 64 && /^[0-9a-fA-F]+$/.test(stripped)) {
|
|
155
|
+
return stripped.toLowerCase();
|
|
156
|
+
}
|
|
157
|
+
return createHash("sha256").update(seed, "utf8").digest("hex");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ── flow ─────────────────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
const seedHex = seedToHexString(seedInput);
|
|
163
|
+
console.error(
|
|
164
|
+
`[bootstrap] seed=${seedHex.slice(0, 8)}… (${seedInput === seedHex ? "verbatim hex" : "hashed"})`,
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const indexer = new URL(indexerUrl);
|
|
168
|
+
const wsScheme = indexer.protocol === "https:" ? "wss:" : "ws:";
|
|
169
|
+
const indexerWS = `${wsScheme}//${indexer.host}${indexer.pathname}/ws`;
|
|
170
|
+
|
|
171
|
+
const dappConfig = new ProfileConfig("standalone", {
|
|
172
|
+
indexer: indexerUrl,
|
|
173
|
+
indexerWS,
|
|
174
|
+
node: nodeRpcUrl,
|
|
175
|
+
proofServer: proofServerUrl,
|
|
176
|
+
});
|
|
177
|
+
console.error(
|
|
178
|
+
`[bootstrap] endpoints: indexer=${dappConfig.indexer} node=${dappConfig.node} proof=${dappConfig.proofServer}`,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
console.error("[bootstrap] step 1/7 build wallet, wait for funds…");
|
|
182
|
+
const walletCtx = await buildWalletAndWaitForFunds(dappConfig, seedHex);
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
console.error("[bootstrap] step 2/7 register for dust generation…");
|
|
186
|
+
await registerForDustGeneration(
|
|
187
|
+
walletCtx.wallet,
|
|
188
|
+
walletCtx.unshieldedKeystore,
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
console.error("[bootstrap] step 3/7 configure providers…");
|
|
192
|
+
const providers = await configureProviders(walletCtx, dappConfig);
|
|
193
|
+
|
|
194
|
+
console.error("[bootstrap] step 4/7 init DID private state…");
|
|
195
|
+
const privateState = await initPrivateState(providers);
|
|
196
|
+
|
|
197
|
+
console.error("[bootstrap] step 5/7 createDID (deploy contract)…");
|
|
198
|
+
const contract = await retryOnDustShortage("createDID", () =>
|
|
199
|
+
createDID(providers, privateState),
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const contractAddress = parseContractAddress(
|
|
203
|
+
contract.deployTxData.public.contractAddress,
|
|
204
|
+
);
|
|
205
|
+
const didString = createMidnightDIDString(
|
|
206
|
+
contractAddress,
|
|
207
|
+
getMidnightNetwork(),
|
|
208
|
+
);
|
|
209
|
+
console.error(`[bootstrap] DID deployed: ${didString}`);
|
|
210
|
+
|
|
211
|
+
// Ed25519 authentication
|
|
212
|
+
const edKid = `${didString}#key-auth`;
|
|
213
|
+
const edSecret = randomSecret32();
|
|
214
|
+
const edPublic = ed25519.getPublicKey(edSecret);
|
|
215
|
+
const edVm = createVerificationMethod({
|
|
216
|
+
id: edKid,
|
|
217
|
+
type: VerificationMethodType.JsonWebKey,
|
|
218
|
+
controller: didString,
|
|
219
|
+
publicKeyJwk: {
|
|
220
|
+
kty: KeyType.OKP,
|
|
221
|
+
crv: CurveType.Ed25519,
|
|
222
|
+
x: encodeBase64Url(edPublic),
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
console.error(
|
|
226
|
+
"[bootstrap] step 6/7 attach Ed25519 + authentication relation…",
|
|
227
|
+
);
|
|
228
|
+
await retryOnDustShortage("addVerificationMethod(ed25519)", () =>
|
|
229
|
+
addVerificationMethod(contract, edVm),
|
|
230
|
+
);
|
|
231
|
+
await retryOnDustShortage(
|
|
232
|
+
"addVerificationMethodRelation(authentication)",
|
|
233
|
+
() =>
|
|
234
|
+
addVerificationMethodRelation(
|
|
235
|
+
contract,
|
|
236
|
+
providers,
|
|
237
|
+
VerificationMethodRelationType.Authentication,
|
|
238
|
+
edKid,
|
|
239
|
+
),
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Jubjub assertion
|
|
243
|
+
const jubKid = `${didString}#key-assert`;
|
|
244
|
+
const jubSecret = randomSecret32();
|
|
245
|
+
const jubPublic = deriveJubjubPublicKeyFromSeed(jubSecret);
|
|
246
|
+
console.error(
|
|
247
|
+
"[bootstrap] step 7/7 attach Jubjub + assertionMethod relation…",
|
|
248
|
+
);
|
|
249
|
+
await retryOnDustShortage("addSchnorrJubjubVerificationMethod", () =>
|
|
250
|
+
addSchnorrJubjubVerificationMethod(contract, {
|
|
251
|
+
id: jubKid,
|
|
252
|
+
publicKey: jubPublic,
|
|
253
|
+
}),
|
|
254
|
+
);
|
|
255
|
+
await retryOnDustShortage(
|
|
256
|
+
"addVerificationMethodRelation(assertionMethod)",
|
|
257
|
+
() =>
|
|
258
|
+
addVerificationMethodRelation(
|
|
259
|
+
contract,
|
|
260
|
+
providers,
|
|
261
|
+
VerificationMethodRelationType.AssertionMethod,
|
|
262
|
+
jubKid,
|
|
263
|
+
),
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
// Verify. The relation arrays may contain bare fragment ids
|
|
267
|
+
// (`#key-auth`) or full DID URLs depending on how the resolver
|
|
268
|
+
// serialised them. We compare by fragment only — that's what
|
|
269
|
+
// the api package's test suite does (`hasSameMethodFragment`
|
|
270
|
+
// in `src/test/did.api.test.ts`).
|
|
271
|
+
const toFragment = (s: string): string => {
|
|
272
|
+
const trimmed = s.trim();
|
|
273
|
+
const hash = trimmed.indexOf("#");
|
|
274
|
+
return hash >= 0 ? trimmed.slice(hash) : `#${trimmed}`;
|
|
275
|
+
};
|
|
276
|
+
type VerificationMethodReference = string | { id: string };
|
|
277
|
+
const referenceToFragment = (
|
|
278
|
+
reference: VerificationMethodReference,
|
|
279
|
+
): string =>
|
|
280
|
+
toFragment(typeof reference === "string" ? reference : reference.id);
|
|
281
|
+
|
|
282
|
+
const resolution = await resolve(providers, contract);
|
|
283
|
+
const doc = resolution?.didDocument;
|
|
284
|
+
const authFragments = (doc?.authentication ?? []).map(referenceToFragment);
|
|
285
|
+
const assertFragments = (doc?.assertionMethod ?? []).map(referenceToFragment);
|
|
286
|
+
if (!authFragments.includes(toFragment(edKid))) {
|
|
287
|
+
throw new Error(
|
|
288
|
+
`Ed25519 kid ${edKid} (${toFragment(edKid)}) not in authentication relation — got ${JSON.stringify(authFragments)}`,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
if (!assertFragments.includes(toFragment(jubKid))) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
`Jubjub kid ${jubKid} (${toFragment(jubKid)}) not in assertionMethod relation — got ${JSON.stringify(assertFragments)}`,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const out = {
|
|
298
|
+
did: didString,
|
|
299
|
+
ed25519: {
|
|
300
|
+
kid: edKid,
|
|
301
|
+
secret_hex: Buffer.from(edSecret).toString("hex"),
|
|
302
|
+
},
|
|
303
|
+
jubjub: {
|
|
304
|
+
kid: jubKid,
|
|
305
|
+
secret_hex: Buffer.from(jubSecret).toString("hex"),
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
writeFileSync(outPath, JSON.stringify(out, null, 2));
|
|
309
|
+
console.log(`Wrote ${outPath}`);
|
|
310
|
+
console.log(`Issuer DID: ${didString}`);
|
|
311
|
+
} finally {
|
|
312
|
+
await walletCtx.wallet.stop();
|
|
313
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildWalletAndWaitForFunds,
|
|
3
|
+
configureProviders,
|
|
4
|
+
createDID,
|
|
5
|
+
initPrivateState,
|
|
6
|
+
resolve,
|
|
7
|
+
StandaloneConfig,
|
|
8
|
+
} from "@midnight-ntwrk/midnight-did-api";
|
|
9
|
+
|
|
10
|
+
const seed = process.env.MIDNIGHT_WALLET_SEED;
|
|
11
|
+
if (seed === undefined || seed.length === 0) {
|
|
12
|
+
throw new Error("Set MIDNIGHT_WALLET_SEED to deploy a DID");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const bigintReplacer = (_key: string, value: unknown) =>
|
|
16
|
+
typeof value === "bigint" ? value.toString() : value;
|
|
17
|
+
|
|
18
|
+
const config = new StandaloneConfig();
|
|
19
|
+
const walletContext = await buildWalletAndWaitForFunds(config, seed);
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const providers = await configureProviders(walletContext, config);
|
|
23
|
+
const privateState = await initPrivateState(providers);
|
|
24
|
+
const didContract = await createDID(providers, privateState);
|
|
25
|
+
const resolution = await resolve(providers, didContract);
|
|
26
|
+
|
|
27
|
+
console.log(
|
|
28
|
+
JSON.stringify(
|
|
29
|
+
{
|
|
30
|
+
contractAddress: didContract.deployTxData.public.contractAddress,
|
|
31
|
+
did: resolution?.didDocument.id,
|
|
32
|
+
resolution,
|
|
33
|
+
},
|
|
34
|
+
bigintReplacer,
|
|
35
|
+
2,
|
|
36
|
+
),
|
|
37
|
+
);
|
|
38
|
+
} finally {
|
|
39
|
+
await walletContext.wallet.stop();
|
|
40
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addService,
|
|
3
|
+
addVerificationMethod,
|
|
4
|
+
addVerificationMethodRelation,
|
|
5
|
+
buildWalletAndWaitForFunds,
|
|
6
|
+
configureProviders,
|
|
7
|
+
joinContract,
|
|
8
|
+
resolve,
|
|
9
|
+
StandaloneConfig,
|
|
10
|
+
updateService,
|
|
11
|
+
} from "@midnight-ntwrk/midnight-did-api";
|
|
12
|
+
import {
|
|
13
|
+
createService,
|
|
14
|
+
createVerificationMethod,
|
|
15
|
+
CurveType,
|
|
16
|
+
KeyType,
|
|
17
|
+
VerificationMethodRelationType,
|
|
18
|
+
VerificationMethodType,
|
|
19
|
+
} from "@midnight-ntwrk/midnight-did-domain";
|
|
20
|
+
|
|
21
|
+
const seed = process.env.MIDNIGHT_WALLET_SEED;
|
|
22
|
+
const contractAddress = process.env.MIDNIGHT_DID_CONTRACT_ADDRESS;
|
|
23
|
+
|
|
24
|
+
if (seed === undefined || seed.length === 0) {
|
|
25
|
+
throw new Error("Set MIDNIGHT_WALLET_SEED to update a DID");
|
|
26
|
+
}
|
|
27
|
+
if (contractAddress === undefined || contractAddress.length === 0) {
|
|
28
|
+
throw new Error("Set MIDNIGHT_DID_CONTRACT_ADDRESS to update a DID");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const bigintReplacer = (_key: string, value: unknown) =>
|
|
32
|
+
typeof value === "bigint" ? value.toString() : value;
|
|
33
|
+
|
|
34
|
+
const config = new StandaloneConfig();
|
|
35
|
+
const walletContext = await buildWalletAndWaitForFunds(config, seed);
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const providers = await configureProviders(walletContext, config);
|
|
39
|
+
const didContract = await joinContract(providers, contractAddress);
|
|
40
|
+
const before = await resolve(providers, didContract);
|
|
41
|
+
if (before === null) {
|
|
42
|
+
throw new Error(`No DID contract found at ${contractAddress}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const did = before.didDocument.id;
|
|
46
|
+
const verificationMethod = createVerificationMethod({
|
|
47
|
+
id: "#example-key-1",
|
|
48
|
+
type: VerificationMethodType.JsonWebKey,
|
|
49
|
+
controller: did,
|
|
50
|
+
publicKeyJwk: {
|
|
51
|
+
kty: KeyType.OKP,
|
|
52
|
+
crv: CurveType.Ed25519,
|
|
53
|
+
// Example-only placeholder key material. Use a real holder/issuer key in applications.
|
|
54
|
+
x: "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE",
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await addVerificationMethod(didContract, verificationMethod);
|
|
59
|
+
await addVerificationMethodRelation(
|
|
60
|
+
didContract,
|
|
61
|
+
providers,
|
|
62
|
+
VerificationMethodRelationType.Authentication,
|
|
63
|
+
verificationMethod.id,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const service = createService({
|
|
67
|
+
id: "#didcomm",
|
|
68
|
+
type: "DIDCommMessaging",
|
|
69
|
+
serviceEndpoint: "https://example.com/didcomm",
|
|
70
|
+
});
|
|
71
|
+
await addService(didContract, service);
|
|
72
|
+
await updateService(
|
|
73
|
+
didContract,
|
|
74
|
+
createService({
|
|
75
|
+
...service,
|
|
76
|
+
serviceEndpoint: "https://example.com/didcomm/v2",
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const after = await resolve(providers, didContract);
|
|
81
|
+
console.log(JSON.stringify(after, bigintReplacer, 2));
|
|
82
|
+
} finally {
|
|
83
|
+
await walletContext.wallet.stop();
|
|
84
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@midnight-ntwrk/midnight-did-api",
|
|
3
|
+
"version": "0.5.0-rc1",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/midnightntwrk/midnight-did.git",
|
|
9
|
+
"directory": "packages/api"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public",
|
|
13
|
+
"registry": "https://registry.npmjs.org/"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=24",
|
|
17
|
+
"pnpm": ">=10"
|
|
18
|
+
},
|
|
19
|
+
"main": "dist/index.js",
|
|
20
|
+
"module": "dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"require": "./dist/index.js",
|
|
26
|
+
"import": "./dist/index.js",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./browser": {
|
|
30
|
+
"types": "./dist/browser.d.ts",
|
|
31
|
+
"import": "./dist/browser.js",
|
|
32
|
+
"default": "./dist/browser.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@midnight-ntwrk/compact-js": "2.5.0",
|
|
37
|
+
"@midnight-ntwrk/compact-runtime": "0.15.0",
|
|
38
|
+
"@midnight-ntwrk/ledger-v8": "8.0.3",
|
|
39
|
+
"@midnight-ntwrk/midnight-js-contracts": "4.0.2",
|
|
40
|
+
"@midnight-ntwrk/midnight-js-http-client-proof-provider": "4.0.2",
|
|
41
|
+
"@midnight-ntwrk/midnight-js-indexer-public-data-provider": "4.0.2",
|
|
42
|
+
"@midnight-ntwrk/midnight-js-level-private-state-provider": "4.0.2",
|
|
43
|
+
"@midnight-ntwrk/midnight-js-network-id": "4.0.2",
|
|
44
|
+
"@midnight-ntwrk/midnight-js-node-zk-config-provider": "4.0.2",
|
|
45
|
+
"@midnight-ntwrk/midnight-js-types": "4.0.2",
|
|
46
|
+
"@midnight-ntwrk/midnight-js-utils": "4.0.2",
|
|
47
|
+
"@midnight-ntwrk/wallet-sdk-dust-wallet": "3.0.0",
|
|
48
|
+
"@midnight-ntwrk/wallet-sdk-facade": "3.0.0",
|
|
49
|
+
"@midnight-ntwrk/wallet-sdk-hd": "3.0.0",
|
|
50
|
+
"@midnight-ntwrk/wallet-sdk-shielded": "2.1.0",
|
|
51
|
+
"@midnight-ntwrk/wallet-sdk-unshielded-wallet": "2.1.0",
|
|
52
|
+
"@noble/curves": "^1.9.7",
|
|
53
|
+
"pino": "^9.7.0",
|
|
54
|
+
"pino-pretty": "^13.0.0",
|
|
55
|
+
"rxjs": "7.8.2",
|
|
56
|
+
"ws": "^8.18.2",
|
|
57
|
+
"zod": "^4.1.0",
|
|
58
|
+
"@midnight-ntwrk/midnight-did": "0.5.0-rc1",
|
|
59
|
+
"@midnight-ntwrk/midnight-did-contract": "0.5.0-rc1",
|
|
60
|
+
"@midnight-ntwrk/midnight-did-domain": "0.5.0-rc1"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"globals": "14.0.0",
|
|
64
|
+
"long": "5.3.2",
|
|
65
|
+
"protobufjs": "7.6.5",
|
|
66
|
+
"@midnight-ntwrk/midnight-did-jubjub-schnorr": "0.5.0-rc1"
|
|
67
|
+
},
|
|
68
|
+
"files": [
|
|
69
|
+
"dist/**",
|
|
70
|
+
"README.md",
|
|
71
|
+
"examples/**",
|
|
72
|
+
"package.json",
|
|
73
|
+
"tsconfig.json",
|
|
74
|
+
"tsconfig.build.json"
|
|
75
|
+
],
|
|
76
|
+
"scripts": {
|
|
77
|
+
"clean": "rm -rf dist",
|
|
78
|
+
"build": "pnpm run clean && tsc -b tsconfig.build.json --force",
|
|
79
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
80
|
+
"typecheck:examples": "tsc -p tsconfig.examples.json --noEmit",
|
|
81
|
+
"test": "vitest run -c vitest.unit.config.ts --passWithNoTests",
|
|
82
|
+
"test:ci": "vitest run -c vitest.unit.config.ts --passWithNoTests",
|
|
83
|
+
"test-api": "vitest run -c vitest.api.config.ts",
|
|
84
|
+
"coverage": "vitest run -c vitest.unit.config.ts --coverage",
|
|
85
|
+
"lint": "eslint src examples",
|
|
86
|
+
"lint:fix": "eslint src examples --fix"
|
|
87
|
+
}
|
|
88
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["src/**/*.ts"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"composite": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"lib": ["ESNext"],
|
|
9
|
+
"target": "ES2022",
|
|
10
|
+
"module": "ESNext",
|
|
11
|
+
"moduleResolution": "Bundler",
|
|
12
|
+
"allowJs": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"noImplicitAny": true,
|
|
15
|
+
"strict": true,
|
|
16
|
+
"isolatedModules": true,
|
|
17
|
+
"sourceMap": true,
|
|
18
|
+
"resolveJsonModule": true,
|
|
19
|
+
"esModuleInterop": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
21
|
+
"baseUrl": "."
|
|
22
|
+
}
|
|
23
|
+
}
|