@miden-sdk/para 0.0.0-bootstrap → 0.16.0-rc.5

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Miden
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,10 +1,49 @@
1
1
  # @miden-sdk/para
2
2
 
3
- **Placeholder — do not install.**
3
+ [![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/0xMiden/miden-para/blob/main/LICENSE)
4
+ [![test](https://github.com/0xMiden/miden-para/actions/workflows/test.yml/badge.svg)](https://github.com/0xMiden/miden-para/actions/workflows/test.yml)
5
+ [![build](https://github.com/0xMiden/miden-para/actions/workflows/build.yml/badge.svg)](https://github.com/0xMiden/miden-para/actions/workflows/build.yml)
4
6
 
5
- npm requires a package to exist before a trusted publisher can be attached to it, so this
6
- `0.0.0-bootstrap` version exists only to reserve the name and let `0xMiden/web-sdk` be
7
- registered as its trusted publisher.
7
+ This is the Miden x Para SDK integration. Below, you'll find instructions for local building and linking the library. If you're looking for React integration, see [Miden x Para x React](./packages/use-miden-para-react/README.md) (package `@miden-sdk/para-react`). If you want to scaffold a fresh Vite `react-ts` app with our Vite config baked in, check [create-miden-para-react](./packages/create-miden-para-react/README.md) (package `@miden-sdk/create-para-react`).
8
8
 
9
- It is published under the `bootstrap` dist-tag, not `latest`, and is deprecated. Real
10
- releases will ship from `0xMiden/web-sdk` with OIDC provenance.
9
+ ## Requirements
10
+
11
+ - **Yarn 1.22.22** (enforced via `packageManager` field)
12
+ - Node.js (compatible with your project)
13
+ - A Para API key. **Production deployments require a Para production API key**; use a non-prod key for local/dev.
14
+
15
+ This project uses Yarn 1.22.22. The version is locked in `package.json` and will be automatically enforced by modern package managers that support the `packageManager` field.
16
+
17
+ ## Peer Dependencies
18
+
19
+ `@miden-sdk/para` expects these packages to be provided by the consuming app. Install matching versions alongside this package to avoid duplicate copies:
20
+
21
+ - `@miden-sdk/miden-sdk@^0.13.0`
22
+ - `@getpara/web-sdk@2.0.0-alpha.73`
23
+
24
+ Example install:
25
+
26
+ ```bash
27
+ yarn add @miden-sdk/para @miden-sdk/miden-sdk@^0.13.0 @getpara/web-sdk@2.0.0-alpha.73
28
+ ```
29
+
30
+ When creating a client with `storageMode` set to `private`, supply an `accountSeed`; the initializer will throw if it is missing so that private accounts remain recoverable.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ yarn install
36
+ ```
37
+
38
+ ## Building
39
+
40
+ ```bash
41
+ yarn build
42
+ ```
43
+
44
+ ## Publishing to npm
45
+
46
+ 1. Update the version in `package.json` (the published package is `@miden-sdk/para`).
47
+ 2. Authenticate with npm if needed: `npm login`.
48
+ 3. Publish: `npm run publish`. The `prepack` hook rebuilds `dist/` and the `postpack` hook moves the generated tarball into `build/`.
49
+ 4. (Optional) Inspect the packed artifact without publishing via `npm pack` and check `build/` for the resulting `miden-sdk-miden-para-<version>.tgz`.
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ evmPkToCommitment: () => import_utils.evmPkToCommitment,
23
+ getUncompressedPublicKeyFromWallet: () => import_utils.getUncompressedPublicKeyFromWallet
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+ __reExport(index_exports, require("./midenClient.js"), module.exports);
27
+ var import_utils = require("./utils.js");
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var midenClient_exports = {};
30
+ __export(midenClient_exports, {
31
+ createParaMidenClient: () => createParaMidenClient,
32
+ signCb: () => signCb
33
+ });
34
+ module.exports = __toCommonJS(midenClient_exports);
35
+ var import_web_sdk = require("@getpara/web-sdk");
36
+ var import_sha3 = require("@noble/hashes/sha3.js");
37
+ var import_utils = require("./utils.js");
38
+ var import_utils2 = require("@noble/hashes/utils.js");
39
+ var import_modalClient = require("./modalClient.js");
40
+ const signCb = (para, wallet, showSigningModal, customSignConfirmStep) => {
41
+ return async (_, signingInputs) => {
42
+ const { SigningInputs } = await import("@miden-sdk/miden-sdk");
43
+ const inputs = SigningInputs.deserialize(signingInputs);
44
+ let commitment = inputs.toCommitment().toHex().slice(2);
45
+ const hashed = (0, import_utils2.bytesToHex)((0, import_sha3.keccak_256)((0, import_utils2.hexToBytes)(commitment)));
46
+ const txSummaryJson = (0, import_utils.txSummaryToJson)(inputs.transactionSummaryPayload());
47
+ if (showSigningModal) {
48
+ const confirmed = await (0, import_modalClient.signingModal)(txSummaryJson);
49
+ if (!confirmed) {
50
+ throw new Error("User cancelled signing");
51
+ }
52
+ }
53
+ if (customSignConfirmStep) {
54
+ await customSignConfirmStep(txSummaryJson);
55
+ }
56
+ console.time("Para Signing Time");
57
+ const res = await para.signMessage({
58
+ walletId: wallet.id,
59
+ messageBase64: (0, import_web_sdk.hexStringToBase64)(hashed)
60
+ });
61
+ console.timeEnd("Para Signing Time");
62
+ const signature = res.signature;
63
+ const sig = (0, import_utils.fromHexSig)(signature);
64
+ return sig;
65
+ };
66
+ };
67
+ async function createAccount(client, publicKey, opts) {
68
+ const { AccountBuilder, AccountComponent, AccountStorageMode } = await import("@miden-sdk/miden-sdk");
69
+ await client.sync();
70
+ let pkc = await (0, import_utils.evmPkToCommitment)(publicKey);
71
+ const accountBuilder = new AccountBuilder(
72
+ (0, import_utils.accountSeedFromStr)(opts.accountSeed) ?? new Uint8Array(32).fill(0)
73
+ );
74
+ const accountStorageMode = opts.storageMode === "private" ? AccountStorageMode.private() : AccountStorageMode.public();
75
+ const account = accountBuilder.withAuthComponent(
76
+ AccountComponent.createAuthComponentFromCommitment(pkc, 1)
77
+ ).storageMode(accountStorageMode).withBasicWalletComponent().build().account;
78
+ if (opts.storageMode !== "private") {
79
+ try {
80
+ await client.accounts.import(account);
81
+ } catch {
82
+ }
83
+ }
84
+ const existing = await client.accounts.get(account.id());
85
+ if (!existing) {
86
+ await client.accounts.insert({ account });
87
+ }
88
+ await client.sync();
89
+ return account.id().toString();
90
+ }
91
+ async function createParaMidenClient(para, wallets, opts, showSigningModal = true, customSignConfirmStep) {
92
+ const evmWallets = wallets.filter((wallet2) => wallet2.type === "EVM");
93
+ if (!evmWallets?.length) {
94
+ throw new Error("No EVM wallets provided");
95
+ }
96
+ const accountKeys = await Promise.all(
97
+ evmWallets.map((w) => (0, import_utils.getUncompressedPublicKeyFromWallet)(para, w))
98
+ );
99
+ const selectedIndex = await (0, import_modalClient.accountSelectionModal)(accountKeys);
100
+ const wallet = evmWallets[selectedIndex] ?? evmWallets[0];
101
+ const publicKey = accountKeys[selectedIndex] ?? accountKeys[0];
102
+ const { MidenClient } = await import("@miden-sdk/miden-sdk");
103
+ if (opts.storageMode === "private" && !opts.accountSeed) {
104
+ throw new Error("accountSeed is required when using private storage mode");
105
+ }
106
+ const signCallback = signCb(
107
+ para,
108
+ wallet,
109
+ showSigningModal,
110
+ customSignConfirmStep
111
+ );
112
+ const noteTransportUrl = opts.noteTransportUrl || opts.nodeTransportUrl || "https://transport.miden.io";
113
+ const client = await MidenClient.create({
114
+ rpcUrl: opts.endpoint,
115
+ noteTransportUrl,
116
+ seed: (0, import_utils.accountSeedFromStr)(opts.seed),
117
+ keystore: {
118
+ getKey: async () => void 0,
119
+ insertKey: async () => {
120
+ },
121
+ sign: signCallback
122
+ },
123
+ autoSync: true
124
+ });
125
+ const accountId = await createAccount(
126
+ client,
127
+ publicKey,
128
+ opts
129
+ );
130
+ return { client, accountId };
131
+ }
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var modalClient_exports = {};
20
+ __export(modalClient_exports, {
21
+ accountSelectionModal: () => accountSelectionModal,
22
+ signingModal: () => signingModal
23
+ });
24
+ module.exports = __toCommonJS(modalClient_exports);
25
+ const createModalShell = (titleText) => {
26
+ const existing = document.getElementById("para-signing-modal");
27
+ if (existing) existing.remove();
28
+ const overlay = document.createElement("div");
29
+ overlay.id = "para-signing-modal";
30
+ Object.assign(overlay.style, {
31
+ position: "fixed",
32
+ inset: "0",
33
+ background: "rgba(0, 0, 0, 0.6)",
34
+ display: "flex",
35
+ alignItems: "center",
36
+ justifyContent: "center",
37
+ zIndex: "9999",
38
+ padding: "16px",
39
+ boxSizing: "border-box",
40
+ color: "#0f172a",
41
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
42
+ });
43
+ const modal = document.createElement("div");
44
+ Object.assign(modal.style, {
45
+ background: "#f8fafc",
46
+ borderRadius: "12px",
47
+ padding: "20px",
48
+ maxWidth: "420px",
49
+ width: "100%",
50
+ boxShadow: "0 12px 40px rgba(15, 23, 42, 0.25)"
51
+ });
52
+ const title = document.createElement("div");
53
+ title.textContent = titleText;
54
+ Object.assign(title.style, {
55
+ fontSize: "16px",
56
+ fontWeight: "600",
57
+ marginBottom: "12px"
58
+ });
59
+ modal.append(title);
60
+ overlay.append(modal);
61
+ return { overlay, modal };
62
+ };
63
+ const createActionsRow = () => {
64
+ const actions = document.createElement("div");
65
+ Object.assign(actions.style, {
66
+ display: "flex",
67
+ gap: "10px",
68
+ justifyContent: "flex-end"
69
+ });
70
+ return actions;
71
+ };
72
+ const createPrimaryButton = (label) => {
73
+ const button = document.createElement("button");
74
+ button.textContent = label;
75
+ Object.assign(button.style, {
76
+ padding: "10px 16px",
77
+ borderRadius: "8px",
78
+ border: "none",
79
+ background: "#0ea5e9",
80
+ color: "#fff",
81
+ cursor: "pointer",
82
+ fontWeight: "600"
83
+ });
84
+ return button;
85
+ };
86
+ const createSecondaryButton = (label) => {
87
+ const button = document.createElement("button");
88
+ button.textContent = label;
89
+ Object.assign(button.style, {
90
+ padding: "10px 16px",
91
+ borderRadius: "8px",
92
+ border: "1px solid #cbd5e1",
93
+ background: "#fff",
94
+ color: "#0f172a",
95
+ cursor: "pointer",
96
+ fontWeight: "600"
97
+ });
98
+ return button;
99
+ };
100
+ const signingModal = (txSummaryJson) => {
101
+ if (typeof document === "undefined") return Promise.resolve(true);
102
+ return new Promise((resolve) => {
103
+ const { overlay, modal } = createModalShell(
104
+ "Do you want to sign this transaction?"
105
+ );
106
+ const txDetails = document.createElement("div");
107
+ Object.assign(txDetails.style, {
108
+ fontSize: "13px",
109
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
110
+ background: "#e2e8f0",
111
+ padding: "10px",
112
+ borderRadius: "8px",
113
+ marginBottom: "16px",
114
+ color: "#0f172a",
115
+ maxHeight: "300px",
116
+ overflowY: "auto"
117
+ });
118
+ const inputSection = document.createElement("div");
119
+ inputSection.style.marginBottom = "12px";
120
+ const inputTitle = document.createElement("div");
121
+ inputTitle.textContent = "Input Notes:";
122
+ inputTitle.style.fontWeight = "600";
123
+ inputTitle.style.marginBottom = "4px";
124
+ inputSection.append(inputTitle);
125
+ if (txSummaryJson.inputNotes.length === 0) {
126
+ const noInputs = document.createElement("div");
127
+ noInputs.textContent = "None";
128
+ noInputs.style.color = "#64748b";
129
+ inputSection.append(noInputs);
130
+ } else {
131
+ txSummaryJson.inputNotes.forEach((note, idx) => {
132
+ const noteDiv = document.createElement("div");
133
+ noteDiv.style.marginBottom = "8px";
134
+ noteDiv.style.paddingLeft = "8px";
135
+ noteDiv.innerHTML = `
136
+ <div><strong>Note ${idx + 1}:</strong> ${note.id}</div>
137
+ <div style="padding-left: 8px; color: #475569;">
138
+ Sender: ${note.sender}<br/>
139
+ Assets: ${note.assets.map((a) => `${a.amount} of ${a.assetId}`).join(", ") || "None"}
140
+ </div>
141
+ `;
142
+ inputSection.append(noteDiv);
143
+ });
144
+ }
145
+ const outputSection = document.createElement("div");
146
+ const outputTitle = document.createElement("div");
147
+ outputTitle.textContent = "Output Notes:";
148
+ outputTitle.style.fontWeight = "600";
149
+ outputTitle.style.marginBottom = "4px";
150
+ outputSection.append(outputTitle);
151
+ if (txSummaryJson.outputNotes.length === 0) {
152
+ const noOutputs = document.createElement("div");
153
+ noOutputs.textContent = "None";
154
+ noOutputs.style.color = "#64748b";
155
+ outputSection.append(noOutputs);
156
+ } else {
157
+ txSummaryJson.outputNotes.forEach((note, idx) => {
158
+ const noteDiv = document.createElement("div");
159
+ noteDiv.style.marginBottom = "8px";
160
+ noteDiv.style.paddingLeft = "8px";
161
+ noteDiv.innerHTML = `
162
+ <div><strong>Note ${idx + 1}:</strong> ${note.id}</div>
163
+ <div style="padding-left: 8px; color: #475569;">
164
+ Type: ${note.noteType}<br/>
165
+ Assets: ${note.assets.map((a) => `${a.amount} of ${a.assetId}`).join(", ") || "None"}
166
+ </div>
167
+ `;
168
+ outputSection.append(noteDiv);
169
+ });
170
+ }
171
+ txDetails.append(inputSection, outputSection);
172
+ const actions = createActionsRow();
173
+ const yesBtn = createPrimaryButton("Yes");
174
+ const noBtn = createSecondaryButton("No");
175
+ const cleanup = () => {
176
+ overlay.remove();
177
+ };
178
+ yesBtn.onclick = () => {
179
+ cleanup();
180
+ resolve(true);
181
+ };
182
+ noBtn.onclick = () => {
183
+ cleanup();
184
+ resolve(false);
185
+ };
186
+ actions.append(noBtn, yesBtn);
187
+ modal.append(txDetails, actions);
188
+ document.body.append(overlay);
189
+ });
190
+ };
191
+ const accountSelectionModal = (accounts) => {
192
+ if (accounts.length === 1 || typeof document === "undefined") {
193
+ return Promise.resolve(0);
194
+ }
195
+ return new Promise((resolve) => {
196
+ const { overlay, modal } = createModalShell("Choose an account to use");
197
+ const list = document.createElement("div");
198
+ Object.assign(list.style, {
199
+ display: "flex",
200
+ flexDirection: "column",
201
+ gap: "8px",
202
+ marginBottom: "16px"
203
+ });
204
+ let selectedIndex = 0;
205
+ const items = [];
206
+ const highlightSelection = () => {
207
+ items.forEach((item, idx) => {
208
+ item.style.borderColor = idx === selectedIndex ? "#0ea5e9" : "#cbd5e1";
209
+ item.style.background = idx === selectedIndex ? "#e0f2fe" : "#e2e8f0";
210
+ });
211
+ };
212
+ const okBtn = createPrimaryButton("Ok");
213
+ okBtn.disabled = !accounts.length;
214
+ accounts.forEach((account, index) => {
215
+ const item = document.createElement("button");
216
+ item.type = "button";
217
+ item.textContent = account;
218
+ Object.assign(item.style, {
219
+ padding: "10px",
220
+ borderRadius: "8px",
221
+ border: "1px solid #cbd5e1",
222
+ background: "#e2e8f0",
223
+ fontSize: "13px",
224
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
225
+ color: "#0f172a",
226
+ wordBreak: "break-all",
227
+ textAlign: "left",
228
+ cursor: "pointer"
229
+ });
230
+ item.onclick = () => {
231
+ selectedIndex = index;
232
+ highlightSelection();
233
+ okBtn.disabled = false;
234
+ };
235
+ items.push(item);
236
+ list.append(item);
237
+ });
238
+ if (items.length) {
239
+ highlightSelection();
240
+ }
241
+ const actions = createActionsRow();
242
+ const cleanup = () => {
243
+ overlay.remove();
244
+ };
245
+ okBtn.onclick = () => {
246
+ cleanup();
247
+ resolve(selectedIndex);
248
+ };
249
+ actions.append(okBtn);
250
+ modal.append(list, actions);
251
+ document.body.append(overlay);
252
+ });
253
+ };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var types_exports = {};
16
+ module.exports = __toCommonJS(types_exports);
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var utils_exports = {};
30
+ __export(utils_exports, {
31
+ accountSeedFromStr: () => accountSeedFromStr,
32
+ evmPkToCommitment: () => evmPkToCommitment,
33
+ fromHexSig: () => fromHexSig,
34
+ getUncompressedPublicKeyFromWallet: () => getUncompressedPublicKeyFromWallet,
35
+ hexToBytes: () => import_utils.hexToBytes,
36
+ txSummaryToJson: () => txSummaryToJson
37
+ });
38
+ module.exports = __toCommonJS(utils_exports);
39
+ var import_utils = require("@noble/hashes/utils.js");
40
+ const fromHexSig = (hexString) => {
41
+ if (hexString.length % 2 !== 0) {
42
+ throw new Error("Invalid string len");
43
+ }
44
+ const sigBytes = (0, import_utils.hexToBytes)(hexString);
45
+ const serialized = new Uint8Array(sigBytes.length + 2);
46
+ serialized[0] = 1;
47
+ serialized.set(sigBytes, 1);
48
+ return serialized;
49
+ };
50
+ const accountSeedFromStr = (str) => {
51
+ if (!str) return;
52
+ const buffer = new Uint8Array(32);
53
+ const bytes = (0, import_utils.utf8ToBytes)(str);
54
+ buffer.set(bytes.slice(0, 32));
55
+ return buffer;
56
+ };
57
+ const evmPkToCommitment = async (uncompressedPublicKey) => {
58
+ const { Felt, Poseidon2, FeltArray } = await import("@miden-sdk/miden-sdk");
59
+ const withoutPrefix = uncompressedPublicKey.slice(4);
60
+ const x = withoutPrefix.slice(0, 64);
61
+ const y = withoutPrefix.slice(64);
62
+ const felts = [...coordToLimbs(x), ...coordToLimbs(y)].map(
63
+ (limb) => new Felt(BigInt(limb))
64
+ );
65
+ return Poseidon2.hashElements(new FeltArray(felts));
66
+ };
67
+ const coordToLimbs = (hex) => {
68
+ const bytes = (0, import_utils.hexToBytes)(hex);
69
+ if (bytes.length !== 32) {
70
+ throw new Error(`Expected a 32-byte coordinate, got ${bytes.length}`);
71
+ }
72
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
73
+ const limbs = [];
74
+ for (let i = 7; i >= 0; i--) {
75
+ limbs.push(view.getUint32(i * 4, false));
76
+ }
77
+ return limbs;
78
+ };
79
+ const getUncompressedPublicKeyFromWallet = async (para, wallet) => {
80
+ if (wallet.publicKey) {
81
+ return wallet.publicKey;
82
+ }
83
+ const { token } = await para.issueJwt();
84
+ const payload = JSON.parse(window.atob(token.split(".")[1]));
85
+ const wallets = payload.data?.connectedWallets;
86
+ if (!wallets) {
87
+ throw new Error("Got invalid jwt token");
88
+ }
89
+ const w = wallets.find((connected) => connected.id === wallet.id);
90
+ if (!w) {
91
+ throw new Error("Wallet Not Found in jwt data");
92
+ }
93
+ if (!w.publicKey) {
94
+ throw new Error("Wallet in jwt data has no public key");
95
+ }
96
+ return w.publicKey;
97
+ };
98
+ const txSummaryToJson = (txSummary) => {
99
+ const inputNotes = txSummary.inputNotes().notes().map((inputNote) => ({
100
+ id: inputNote.id().toString(),
101
+ assets: inputNote.note().assets().fungibleAssets().map((asset) => {
102
+ return {
103
+ assetId: asset.faucetId().toString(),
104
+ amount: asset.amount().toString()
105
+ };
106
+ }),
107
+ sender: inputNote.note().metadata().sender().toString()
108
+ }));
109
+ const outputNotes = txSummary.outputNotes().notes().map((outputNote) => {
110
+ const assets = outputNote.assets();
111
+ if (!assets) {
112
+ throw new Error(
113
+ `Output note ${outputNote.id().toString()} carries no asset data; refusing to summarize a transaction whose assets are unknown`
114
+ );
115
+ }
116
+ return {
117
+ id: outputNote.id().toString(),
118
+ assets: assets.fungibleAssets().map((asset) => {
119
+ return {
120
+ assetId: asset.faucetId().toString(),
121
+ amount: asset.amount().toString()
122
+ };
123
+ }),
124
+ noteType: noteTypeToString(outputNote.metadata().noteType())
125
+ };
126
+ });
127
+ return {
128
+ inputNotes,
129
+ outputNotes
130
+ };
131
+ };
132
+ function noteTypeToString(noteType) {
133
+ switch (noteType) {
134
+ case 1:
135
+ return "public";
136
+ case 0:
137
+ return "private";
138
+ default:
139
+ return "UNKNOWN";
140
+ }
141
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./midenClient.js";
2
+ import {
3
+ evmPkToCommitment,
4
+ getUncompressedPublicKeyFromWallet
5
+ } from "./utils.js";
6
+ export {
7
+ evmPkToCommitment,
8
+ getUncompressedPublicKeyFromWallet
9
+ };
@@ -0,0 +1,109 @@
1
+ import {
2
+ hexStringToBase64
3
+ } from "@getpara/web-sdk";
4
+ import { keccak_256 as keccak256 } from "@noble/hashes/sha3.js";
5
+ import {
6
+ accountSeedFromStr,
7
+ evmPkToCommitment,
8
+ fromHexSig,
9
+ getUncompressedPublicKeyFromWallet,
10
+ txSummaryToJson
11
+ } from "./utils.js";
12
+ import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
13
+ import { accountSelectionModal, signingModal } from "./modalClient.js";
14
+ const signCb = (para, wallet, showSigningModal, customSignConfirmStep) => {
15
+ return async (_, signingInputs) => {
16
+ const { SigningInputs } = await import("@miden-sdk/miden-sdk");
17
+ const inputs = SigningInputs.deserialize(signingInputs);
18
+ let commitment = inputs.toCommitment().toHex().slice(2);
19
+ const hashed = bytesToHex(keccak256(hexToBytes(commitment)));
20
+ const txSummaryJson = txSummaryToJson(inputs.transactionSummaryPayload());
21
+ if (showSigningModal) {
22
+ const confirmed = await signingModal(txSummaryJson);
23
+ if (!confirmed) {
24
+ throw new Error("User cancelled signing");
25
+ }
26
+ }
27
+ if (customSignConfirmStep) {
28
+ await customSignConfirmStep(txSummaryJson);
29
+ }
30
+ console.time("Para Signing Time");
31
+ const res = await para.signMessage({
32
+ walletId: wallet.id,
33
+ messageBase64: hexStringToBase64(hashed)
34
+ });
35
+ console.timeEnd("Para Signing Time");
36
+ const signature = res.signature;
37
+ const sig = fromHexSig(signature);
38
+ return sig;
39
+ };
40
+ };
41
+ async function createAccount(client, publicKey, opts) {
42
+ const { AccountBuilder, AccountComponent, AccountStorageMode } = await import("@miden-sdk/miden-sdk");
43
+ await client.sync();
44
+ let pkc = await evmPkToCommitment(publicKey);
45
+ const accountBuilder = new AccountBuilder(
46
+ accountSeedFromStr(opts.accountSeed) ?? new Uint8Array(32).fill(0)
47
+ );
48
+ const accountStorageMode = opts.storageMode === "private" ? AccountStorageMode.private() : AccountStorageMode.public();
49
+ const account = accountBuilder.withAuthComponent(
50
+ AccountComponent.createAuthComponentFromCommitment(pkc, 1)
51
+ ).storageMode(accountStorageMode).withBasicWalletComponent().build().account;
52
+ if (opts.storageMode !== "private") {
53
+ try {
54
+ await client.accounts.import(account);
55
+ } catch {
56
+ }
57
+ }
58
+ const existing = await client.accounts.get(account.id());
59
+ if (!existing) {
60
+ await client.accounts.insert({ account });
61
+ }
62
+ await client.sync();
63
+ return account.id().toString();
64
+ }
65
+ async function createParaMidenClient(para, wallets, opts, showSigningModal = true, customSignConfirmStep) {
66
+ const evmWallets = wallets.filter((wallet2) => wallet2.type === "EVM");
67
+ if (!evmWallets?.length) {
68
+ throw new Error("No EVM wallets provided");
69
+ }
70
+ const accountKeys = await Promise.all(
71
+ evmWallets.map((w) => getUncompressedPublicKeyFromWallet(para, w))
72
+ );
73
+ const selectedIndex = await accountSelectionModal(accountKeys);
74
+ const wallet = evmWallets[selectedIndex] ?? evmWallets[0];
75
+ const publicKey = accountKeys[selectedIndex] ?? accountKeys[0];
76
+ const { MidenClient } = await import("@miden-sdk/miden-sdk");
77
+ if (opts.storageMode === "private" && !opts.accountSeed) {
78
+ throw new Error("accountSeed is required when using private storage mode");
79
+ }
80
+ const signCallback = signCb(
81
+ para,
82
+ wallet,
83
+ showSigningModal,
84
+ customSignConfirmStep
85
+ );
86
+ const noteTransportUrl = opts.noteTransportUrl || opts.nodeTransportUrl || "https://transport.miden.io";
87
+ const client = await MidenClient.create({
88
+ rpcUrl: opts.endpoint,
89
+ noteTransportUrl,
90
+ seed: accountSeedFromStr(opts.seed),
91
+ keystore: {
92
+ getKey: async () => void 0,
93
+ insertKey: async () => {
94
+ },
95
+ sign: signCallback
96
+ },
97
+ autoSync: true
98
+ });
99
+ const accountId = await createAccount(
100
+ client,
101
+ publicKey,
102
+ opts
103
+ );
104
+ return { client, accountId };
105
+ }
106
+ export {
107
+ createParaMidenClient,
108
+ signCb
109
+ };
@@ -0,0 +1,233 @@
1
+ const createModalShell = (titleText) => {
2
+ const existing = document.getElementById("para-signing-modal");
3
+ if (existing) existing.remove();
4
+ const overlay = document.createElement("div");
5
+ overlay.id = "para-signing-modal";
6
+ Object.assign(overlay.style, {
7
+ position: "fixed",
8
+ inset: "0",
9
+ background: "rgba(0, 0, 0, 0.6)",
10
+ display: "flex",
11
+ alignItems: "center",
12
+ justifyContent: "center",
13
+ zIndex: "9999",
14
+ padding: "16px",
15
+ boxSizing: "border-box",
16
+ color: "#0f172a",
17
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
18
+ });
19
+ const modal = document.createElement("div");
20
+ Object.assign(modal.style, {
21
+ background: "#f8fafc",
22
+ borderRadius: "12px",
23
+ padding: "20px",
24
+ maxWidth: "420px",
25
+ width: "100%",
26
+ boxShadow: "0 12px 40px rgba(15, 23, 42, 0.25)"
27
+ });
28
+ const title = document.createElement("div");
29
+ title.textContent = titleText;
30
+ Object.assign(title.style, {
31
+ fontSize: "16px",
32
+ fontWeight: "600",
33
+ marginBottom: "12px"
34
+ });
35
+ modal.append(title);
36
+ overlay.append(modal);
37
+ return { overlay, modal };
38
+ };
39
+ const createActionsRow = () => {
40
+ const actions = document.createElement("div");
41
+ Object.assign(actions.style, {
42
+ display: "flex",
43
+ gap: "10px",
44
+ justifyContent: "flex-end"
45
+ });
46
+ return actions;
47
+ };
48
+ const createPrimaryButton = (label) => {
49
+ const button = document.createElement("button");
50
+ button.textContent = label;
51
+ Object.assign(button.style, {
52
+ padding: "10px 16px",
53
+ borderRadius: "8px",
54
+ border: "none",
55
+ background: "#0ea5e9",
56
+ color: "#fff",
57
+ cursor: "pointer",
58
+ fontWeight: "600"
59
+ });
60
+ return button;
61
+ };
62
+ const createSecondaryButton = (label) => {
63
+ const button = document.createElement("button");
64
+ button.textContent = label;
65
+ Object.assign(button.style, {
66
+ padding: "10px 16px",
67
+ borderRadius: "8px",
68
+ border: "1px solid #cbd5e1",
69
+ background: "#fff",
70
+ color: "#0f172a",
71
+ cursor: "pointer",
72
+ fontWeight: "600"
73
+ });
74
+ return button;
75
+ };
76
+ const signingModal = (txSummaryJson) => {
77
+ if (typeof document === "undefined") return Promise.resolve(true);
78
+ return new Promise((resolve) => {
79
+ const { overlay, modal } = createModalShell(
80
+ "Do you want to sign this transaction?"
81
+ );
82
+ const txDetails = document.createElement("div");
83
+ Object.assign(txDetails.style, {
84
+ fontSize: "13px",
85
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
86
+ background: "#e2e8f0",
87
+ padding: "10px",
88
+ borderRadius: "8px",
89
+ marginBottom: "16px",
90
+ color: "#0f172a",
91
+ maxHeight: "300px",
92
+ overflowY: "auto"
93
+ });
94
+ const inputSection = document.createElement("div");
95
+ inputSection.style.marginBottom = "12px";
96
+ const inputTitle = document.createElement("div");
97
+ inputTitle.textContent = "Input Notes:";
98
+ inputTitle.style.fontWeight = "600";
99
+ inputTitle.style.marginBottom = "4px";
100
+ inputSection.append(inputTitle);
101
+ if (txSummaryJson.inputNotes.length === 0) {
102
+ const noInputs = document.createElement("div");
103
+ noInputs.textContent = "None";
104
+ noInputs.style.color = "#64748b";
105
+ inputSection.append(noInputs);
106
+ } else {
107
+ txSummaryJson.inputNotes.forEach((note, idx) => {
108
+ const noteDiv = document.createElement("div");
109
+ noteDiv.style.marginBottom = "8px";
110
+ noteDiv.style.paddingLeft = "8px";
111
+ noteDiv.innerHTML = `
112
+ <div><strong>Note ${idx + 1}:</strong> ${note.id}</div>
113
+ <div style="padding-left: 8px; color: #475569;">
114
+ Sender: ${note.sender}<br/>
115
+ Assets: ${note.assets.map((a) => `${a.amount} of ${a.assetId}`).join(", ") || "None"}
116
+ </div>
117
+ `;
118
+ inputSection.append(noteDiv);
119
+ });
120
+ }
121
+ const outputSection = document.createElement("div");
122
+ const outputTitle = document.createElement("div");
123
+ outputTitle.textContent = "Output Notes:";
124
+ outputTitle.style.fontWeight = "600";
125
+ outputTitle.style.marginBottom = "4px";
126
+ outputSection.append(outputTitle);
127
+ if (txSummaryJson.outputNotes.length === 0) {
128
+ const noOutputs = document.createElement("div");
129
+ noOutputs.textContent = "None";
130
+ noOutputs.style.color = "#64748b";
131
+ outputSection.append(noOutputs);
132
+ } else {
133
+ txSummaryJson.outputNotes.forEach((note, idx) => {
134
+ const noteDiv = document.createElement("div");
135
+ noteDiv.style.marginBottom = "8px";
136
+ noteDiv.style.paddingLeft = "8px";
137
+ noteDiv.innerHTML = `
138
+ <div><strong>Note ${idx + 1}:</strong> ${note.id}</div>
139
+ <div style="padding-left: 8px; color: #475569;">
140
+ Type: ${note.noteType}<br/>
141
+ Assets: ${note.assets.map((a) => `${a.amount} of ${a.assetId}`).join(", ") || "None"}
142
+ </div>
143
+ `;
144
+ outputSection.append(noteDiv);
145
+ });
146
+ }
147
+ txDetails.append(inputSection, outputSection);
148
+ const actions = createActionsRow();
149
+ const yesBtn = createPrimaryButton("Yes");
150
+ const noBtn = createSecondaryButton("No");
151
+ const cleanup = () => {
152
+ overlay.remove();
153
+ };
154
+ yesBtn.onclick = () => {
155
+ cleanup();
156
+ resolve(true);
157
+ };
158
+ noBtn.onclick = () => {
159
+ cleanup();
160
+ resolve(false);
161
+ };
162
+ actions.append(noBtn, yesBtn);
163
+ modal.append(txDetails, actions);
164
+ document.body.append(overlay);
165
+ });
166
+ };
167
+ const accountSelectionModal = (accounts) => {
168
+ if (accounts.length === 1 || typeof document === "undefined") {
169
+ return Promise.resolve(0);
170
+ }
171
+ return new Promise((resolve) => {
172
+ const { overlay, modal } = createModalShell("Choose an account to use");
173
+ const list = document.createElement("div");
174
+ Object.assign(list.style, {
175
+ display: "flex",
176
+ flexDirection: "column",
177
+ gap: "8px",
178
+ marginBottom: "16px"
179
+ });
180
+ let selectedIndex = 0;
181
+ const items = [];
182
+ const highlightSelection = () => {
183
+ items.forEach((item, idx) => {
184
+ item.style.borderColor = idx === selectedIndex ? "#0ea5e9" : "#cbd5e1";
185
+ item.style.background = idx === selectedIndex ? "#e0f2fe" : "#e2e8f0";
186
+ });
187
+ };
188
+ const okBtn = createPrimaryButton("Ok");
189
+ okBtn.disabled = !accounts.length;
190
+ accounts.forEach((account, index) => {
191
+ const item = document.createElement("button");
192
+ item.type = "button";
193
+ item.textContent = account;
194
+ Object.assign(item.style, {
195
+ padding: "10px",
196
+ borderRadius: "8px",
197
+ border: "1px solid #cbd5e1",
198
+ background: "#e2e8f0",
199
+ fontSize: "13px",
200
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
201
+ color: "#0f172a",
202
+ wordBreak: "break-all",
203
+ textAlign: "left",
204
+ cursor: "pointer"
205
+ });
206
+ item.onclick = () => {
207
+ selectedIndex = index;
208
+ highlightSelection();
209
+ okBtn.disabled = false;
210
+ };
211
+ items.push(item);
212
+ list.append(item);
213
+ });
214
+ if (items.length) {
215
+ highlightSelection();
216
+ }
217
+ const actions = createActionsRow();
218
+ const cleanup = () => {
219
+ overlay.remove();
220
+ };
221
+ okBtn.onclick = () => {
222
+ cleanup();
223
+ resolve(selectedIndex);
224
+ };
225
+ actions.append(okBtn);
226
+ modal.append(list, actions);
227
+ document.body.append(overlay);
228
+ });
229
+ };
230
+ export {
231
+ accountSelectionModal,
232
+ signingModal
233
+ };
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "module",
3
+ "sideEffects": false
4
+ }
File without changes
@@ -0,0 +1,111 @@
1
+ import { hexToBytes, utf8ToBytes } from "@noble/hashes/utils.js";
2
+ const fromHexSig = (hexString) => {
3
+ if (hexString.length % 2 !== 0) {
4
+ throw new Error("Invalid string len");
5
+ }
6
+ const sigBytes = hexToBytes(hexString);
7
+ const serialized = new Uint8Array(sigBytes.length + 2);
8
+ serialized[0] = 1;
9
+ serialized.set(sigBytes, 1);
10
+ return serialized;
11
+ };
12
+ const accountSeedFromStr = (str) => {
13
+ if (!str) return;
14
+ const buffer = new Uint8Array(32);
15
+ const bytes = utf8ToBytes(str);
16
+ buffer.set(bytes.slice(0, 32));
17
+ return buffer;
18
+ };
19
+ const evmPkToCommitment = async (uncompressedPublicKey) => {
20
+ const { Felt, Poseidon2, FeltArray } = await import("@miden-sdk/miden-sdk");
21
+ const withoutPrefix = uncompressedPublicKey.slice(4);
22
+ const x = withoutPrefix.slice(0, 64);
23
+ const y = withoutPrefix.slice(64);
24
+ const felts = [...coordToLimbs(x), ...coordToLimbs(y)].map(
25
+ (limb) => new Felt(BigInt(limb))
26
+ );
27
+ return Poseidon2.hashElements(new FeltArray(felts));
28
+ };
29
+ const coordToLimbs = (hex) => {
30
+ const bytes = hexToBytes(hex);
31
+ if (bytes.length !== 32) {
32
+ throw new Error(`Expected a 32-byte coordinate, got ${bytes.length}`);
33
+ }
34
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
35
+ const limbs = [];
36
+ for (let i = 7; i >= 0; i--) {
37
+ limbs.push(view.getUint32(i * 4, false));
38
+ }
39
+ return limbs;
40
+ };
41
+ const getUncompressedPublicKeyFromWallet = async (para, wallet) => {
42
+ if (wallet.publicKey) {
43
+ return wallet.publicKey;
44
+ }
45
+ const { token } = await para.issueJwt();
46
+ const payload = JSON.parse(window.atob(token.split(".")[1]));
47
+ const wallets = payload.data?.connectedWallets;
48
+ if (!wallets) {
49
+ throw new Error("Got invalid jwt token");
50
+ }
51
+ const w = wallets.find((connected) => connected.id === wallet.id);
52
+ if (!w) {
53
+ throw new Error("Wallet Not Found in jwt data");
54
+ }
55
+ if (!w.publicKey) {
56
+ throw new Error("Wallet in jwt data has no public key");
57
+ }
58
+ return w.publicKey;
59
+ };
60
+ const txSummaryToJson = (txSummary) => {
61
+ const inputNotes = txSummary.inputNotes().notes().map((inputNote) => ({
62
+ id: inputNote.id().toString(),
63
+ assets: inputNote.note().assets().fungibleAssets().map((asset) => {
64
+ return {
65
+ assetId: asset.faucetId().toString(),
66
+ amount: asset.amount().toString()
67
+ };
68
+ }),
69
+ sender: inputNote.note().metadata().sender().toString()
70
+ }));
71
+ const outputNotes = txSummary.outputNotes().notes().map((outputNote) => {
72
+ const assets = outputNote.assets();
73
+ if (!assets) {
74
+ throw new Error(
75
+ `Output note ${outputNote.id().toString()} carries no asset data; refusing to summarize a transaction whose assets are unknown`
76
+ );
77
+ }
78
+ return {
79
+ id: outputNote.id().toString(),
80
+ assets: assets.fungibleAssets().map((asset) => {
81
+ return {
82
+ assetId: asset.faucetId().toString(),
83
+ amount: asset.amount().toString()
84
+ };
85
+ }),
86
+ noteType: noteTypeToString(outputNote.metadata().noteType())
87
+ };
88
+ });
89
+ return {
90
+ inputNotes,
91
+ outputNotes
92
+ };
93
+ };
94
+ function noteTypeToString(noteType) {
95
+ switch (noteType) {
96
+ case 1:
97
+ return "public";
98
+ case 0:
99
+ return "private";
100
+ default:
101
+ return "UNKNOWN";
102
+ }
103
+ }
104
+ export {
105
+ accountSeedFromStr,
106
+ evmPkToCommitment,
107
+ fromHexSig,
108
+ getUncompressedPublicKeyFromWallet,
109
+ hexToBytes,
110
+ txSummaryToJson
111
+ };
@@ -0,0 +1,4 @@
1
+ export * from "./midenClient.js";
2
+ export { evmPkToCommitment, getUncompressedPublicKeyFromWallet, } from "./utils.js";
3
+ export type { MidenAccountOpts, Opts, MidenAccountStorageMode, TxSummaryJson, } from "./types.js";
4
+ export type { CustomSignConfirmStep } from "./midenClient.js";
@@ -0,0 +1,19 @@
1
+ import { ParaWeb, Wallet } from "@getpara/web-sdk";
2
+ import type { Opts, TxSummaryJson } from "./types.js";
3
+ import type { MidenClient } from "@miden-sdk/miden-sdk";
4
+ export type CustomSignConfirmStep = (txSummaryJson: TxSummaryJson) => Promise<unknown>;
5
+ /**
6
+ * Creates a signing callback that routes Miden signing requests through Para.
7
+ * Prompts the user with a modal before delegating the keccak-hashed message to Para's signer,
8
+ * and optionally runs a custom confirmation step in between.
9
+ */
10
+ export declare const signCb: (para: ParaWeb, wallet: Wallet, showSigningModal: boolean, customSignConfirmStep?: CustomSignConfirmStep) => (_: Uint8Array, signingInputs: Uint8Array) => Promise<Uint8Array<ArrayBuffer>>;
11
+ /**
12
+ * Builds a MidenClient wired to Para wallets and ensures an account exists for the user.
13
+ * Filters to EVM wallets, prompts for selection, creates the client, and
14
+ * hydrates or creates the corresponding Miden account before returning the client + account id.
15
+ */
16
+ export declare function createParaMidenClient(para: ParaWeb, wallets: Wallet[], opts: Opts, showSigningModal?: boolean, customSignConfirmStep?: CustomSignConfirmStep): Promise<{
17
+ client: MidenClient;
18
+ accountId: string;
19
+ }>;
@@ -0,0 +1,11 @@
1
+ import { TxSummaryJson } from "./types";
2
+ /**
3
+ * Shows a lightweight confirmation modal for signing a hashed transaction.
4
+ * Resolves to true when the user confirms, false when cancelled; no-op on the server.
5
+ */
6
+ export declare const signingModal: (txSummaryJson: TxSummaryJson) => Promise<boolean>;
7
+ /**
8
+ * Shows a selectable list of account commitments and resolves with the chosen index.
9
+ * Returns 0 immediately when only one account is provided or when running server-side.
10
+ */
11
+ export declare const accountSelectionModal: (accounts: string[]) => Promise<number>;
@@ -0,0 +1,34 @@
1
+ /** @public */
2
+ export interface MidenClientOpts {
3
+ endpoint?: string;
4
+ noteTransportUrl?: string;
5
+ /**
6
+ * @deprecated Use noteTransportUrl instead
7
+ */
8
+ nodeTransportUrl?: string;
9
+ seed?: string;
10
+ }
11
+ export type MidenAccountStorageMode = "public" | "private";
12
+ export interface MidenAccountOpts {
13
+ accountSeed?: string;
14
+ storageMode: MidenAccountStorageMode;
15
+ }
16
+ export type Opts = MidenClientOpts & MidenAccountOpts;
17
+ interface NoteIdAndAsset {
18
+ id: string;
19
+ assets: {
20
+ assetId: string;
21
+ amount: string;
22
+ }[];
23
+ }
24
+ interface InputNoteSender {
25
+ sender: string;
26
+ }
27
+ interface OutputNoteType {
28
+ noteType: string;
29
+ }
30
+ export interface TxSummaryJson {
31
+ inputNotes: (NoteIdAndAsset & InputNoteSender)[];
32
+ outputNotes: (NoteIdAndAsset & OutputNoteType)[];
33
+ }
34
+ export {};
@@ -0,0 +1,33 @@
1
+ import ParaWeb, { Wallet } from "@getpara/web-sdk";
2
+ import type { TransactionSummary } from "@miden-sdk/miden-sdk";
3
+ import { hexToBytes } from "@noble/hashes/utils.js";
4
+ import { TxSummaryJson } from "./types";
5
+ /** @public */
6
+ export { hexToBytes };
7
+ /**
8
+ * Converts a Para hex signature into the serialized format expected by Miden.
9
+ * Prefixes the auth scheme byte and appends the extra padding byte required by current crypto libs.
10
+ */
11
+ export declare const fromHexSig: (hexString: string) => Uint8Array<ArrayBuffer>;
12
+ /**
13
+ * Derives a 32-byte seed buffer from a UTF-8 string, truncating when longer than 32 bytes.
14
+ */
15
+ export declare const accountSeedFromStr: (str?: string) => Uint8Array<ArrayBuffer> | undefined;
16
+ /**
17
+ * Converts an uncompressed EVM public key into a Miden commitment.
18
+ * Assumes input format `0x04${x}${y}` where x and y are 64-char hex strings.
19
+ *
20
+ * The protocol commits to the affine point as Poseidon2 over 16 field elements:
21
+ * the x coordinate then the y coordinate, each as eight 32-bit limbs in
22
+ * little-endian limb order. 0.15 hashed a different preimage — nine felts
23
+ * packed from the 33-byte compressed SEC1 encoding — so a commitment computed
24
+ * by an older release will not match one computed here.
25
+ */
26
+ export declare const evmPkToCommitment: (uncompressedPublicKey: string) => Promise<import("@miden-sdk/miden-sdk").Word>;
27
+ /**
28
+ * Retrieves the uncompressed public key for a Para wallet, falling back to JWT data when absent.
29
+ * Throws rather than returning undefined: callers derive the account commitment from this value,
30
+ * so an absent key is an error, not a state to propagate.
31
+ */
32
+ export declare const getUncompressedPublicKeyFromWallet: (para: ParaWeb, wallet: Wallet) => Promise<string>;
33
+ export declare const txSummaryToJson: (txSummary: TransactionSummary) => TxSummaryJson;
package/package.json CHANGED
@@ -1,18 +1,73 @@
1
1
  {
2
2
  "name": "@miden-sdk/para",
3
- "version": "0.0.0-bootstrap",
4
- "description": "Reserved name. Placeholder published only to allow an npm trusted publisher to be attached; do not install.",
3
+ "version": "0.16.0-rc.5",
4
+ "description": "Miden x Para Integration",
5
5
  "license": "MIT",
6
6
  "author": "Miden Contributors",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/0xMiden/web-sdk.git"
9
+ "url": "git+https://github.com/0xMiden/web-sdk.git",
10
+ "directory": "packages/para/core"
10
11
  },
12
+ "homepage": "https://github.com/0xMiden/web-sdk",
13
+ "readmeFilename": "README.md",
11
14
  "bugs": {
12
15
  "url": "https://github.com/0xMiden/web-sdk/issues"
13
16
  },
14
- "homepage": "https://github.com/0xMiden/web-sdk",
17
+ "dependencies": {
18
+ "@noble/hashes": "^2.0.1"
19
+ },
20
+ "devDependencies": {
21
+ "@getpara/web-sdk": "^2.11.0",
22
+ "@types/react": "^19.0.0",
23
+ "esbuild": "^0.24.0",
24
+ "eslint": "^9.39.1",
25
+ "glob": "^11.0.1",
26
+ "prettier": "^3.7.3",
27
+ "puppeteer": "^24.4.0",
28
+ "react": "^19.2.0",
29
+ "react-test-renderer": "^19.2.0",
30
+ "typescript": "^5.8.3",
31
+ "@miden-sdk/miden-sdk": "0.16.0-rc.5"
32
+ },
33
+ "peerDependencies": {
34
+ "@getpara/web-sdk": "^2.11.0",
35
+ "@miden-sdk/miden-sdk": "^0.16.0-rc.5"
36
+ },
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/types/index.d.ts",
40
+ "import": "./dist/esm/index.js",
41
+ "require": "./dist/cjs/index.js"
42
+ }
43
+ },
15
44
  "files": [
16
- "README.md"
17
- ]
18
- }
45
+ "dist",
46
+ "package.json",
47
+ "docs/INTEGRATIONS.md"
48
+ ],
49
+ "main": "dist/cjs/index.js",
50
+ "module": "dist/esm/index.js",
51
+ "sideEffects": false,
52
+ "types": "dist/types/index.d.ts",
53
+ "typings": "dist/types/index.d.ts",
54
+ "keywords": [
55
+ "miden",
56
+ "para",
57
+ "zk",
58
+ "wallet"
59
+ ],
60
+ "publishConfig": {
61
+ "access": "public"
62
+ },
63
+ "scripts": {
64
+ "test": "node --test",
65
+ "build": "rm -rf dist && node ./scripts/build.mjs && npm run build:types",
66
+ "build:cjs": "rm -rf dist/cjs && tsc --module commonjs --outDir dist/cjs && printf '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
67
+ "build:esm": "rm -rf dist/esm && tsc --module es6 --outDir dist/esm && printf '{\"type\":\"module\",\"sideEffects\":false}' > dist/esm/package.json",
68
+ "build:types": "rm -rf dist/types && tsc --module es2020 --declarationDir dist/types --emitDeclarationOnly --declaration",
69
+ "format": "pnpm exec prettier \"**/*.{js,jsx,ts,tsx}\" --write && pnpm exec eslint . --fix",
70
+ "format-check": "pnpm exec prettier \"**/*.{js,jsx,ts,tsx}\" && pnpm exec eslint",
71
+ "old-build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types"
72
+ }
73
+ }