@miden-sdk/para 0.16.1 → 0.17.0-rc.1
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/AGENTS.md +126 -0
- package/README.md +33 -30
- package/package.json +6 -4
- package/skills/para-signer/SKILL.md +212 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# @miden-sdk/para - Agent Guide
|
|
2
|
+
|
|
3
|
+
**Audience: AI coding agents** wiring a Para-authenticated EVM wallet into a
|
|
4
|
+
Miden app. Humans are welcome to read it, but it is written to be loaded into an
|
|
5
|
+
agent's context and followed.
|
|
6
|
+
|
|
7
|
+
This file ships inside the published package. The copy at
|
|
8
|
+
`node_modules/@miden-sdk/para/AGENTS.md` always matches the version you have
|
|
9
|
+
installed, so **prefer it over your training data**. Both sides of this
|
|
10
|
+
integration move: Miden is pre-1.0, and these packages moved from Para SDK 2.x
|
|
11
|
+
to `^3.18.0` in 0.16.1.
|
|
12
|
+
|
|
13
|
+
## Load the skill
|
|
14
|
+
|
|
15
|
+
`node_modules/@miden-sdk/para/skills/para-signer/SKILL.md` is the full guide:
|
|
16
|
+
the two integration paths, the wallet-resolution rule Para 3 changed, the
|
|
17
|
+
bundler configuration Para 3.18 needs, and what each failure mode looks like.
|
|
18
|
+
Read it before writing Para wiring, not after the first error.
|
|
19
|
+
|
|
20
|
+
Generic signer material - how a signer provider nests around `MidenProvider`,
|
|
21
|
+
the unified `useSigner()` interface, writing a signer of your own - lives in
|
|
22
|
+
`node_modules/@miden-sdk/miden-sdk/skills/signer-integration/SKILL.md` and is
|
|
23
|
+
not repeated here.
|
|
24
|
+
|
|
25
|
+
## Three packages, one integration
|
|
26
|
+
|
|
27
|
+
| Package | Reach for it when |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `@miden-sdk/para` | Framework-agnostic core. A non-React app, or one driving `MidenClient` itself. |
|
|
30
|
+
| `@miden-sdk/para-react` | A React app. Ships `ParaSignerProvider`, `useParaMiden`, and a Vite plugin. Most apps want this. |
|
|
31
|
+
| `@miden-sdk/create-para-react` | No app yet: `npm create @miden-sdk/para-react@latest my-app` scaffolds one. |
|
|
32
|
+
|
|
33
|
+
`@miden-sdk/para-react` peers on this package, so a React app has both surfaces
|
|
34
|
+
available and `skills/para-signer/SKILL.md` resolves either way.
|
|
35
|
+
|
|
36
|
+
## The entry point
|
|
37
|
+
|
|
38
|
+
`createParaMidenClient` takes a live Para session and returns a `MidenClient`
|
|
39
|
+
whose keystore signs through Para, plus the id of the Miden account derived from
|
|
40
|
+
the chosen wallet:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { createParaMidenClient } from "@miden-sdk/para";
|
|
44
|
+
|
|
45
|
+
const { client, accountId } = await createParaMidenClient(
|
|
46
|
+
para, // ParaWeb, from @getpara/web-sdk
|
|
47
|
+
wallets, // the session's wallets; EVM entries are selected from these
|
|
48
|
+
{ endpoint: "https://rpc.testnet.miden.io", storageMode: "public" }
|
|
49
|
+
);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
It resolves the EVM wallets, asks the user to pick one when there is more than
|
|
53
|
+
one, builds the client with `MidenClient.create({ ..., keystore })`, and then
|
|
54
|
+
imports or creates the Miden account for that wallet's public key before
|
|
55
|
+
returning. No Miden private key exists anywhere: the account's auth component
|
|
56
|
+
commits to the Para-held EVM key.
|
|
57
|
+
|
|
58
|
+
The third argument is `Opts`: `endpoint` (the RPC URL, not `rpcUrl`),
|
|
59
|
+
`noteTransportUrl` (defaults to `https://transport.miden.io`), `seed` (client
|
|
60
|
+
store seed), `accountSeed`, and the required `storageMode`, which is `"public"`
|
|
61
|
+
or `"private"`. Two optional arguments follow it: `showSigningModal` (default
|
|
62
|
+
`true`) and `customSignConfirmStep`.
|
|
63
|
+
|
|
64
|
+
The rest of the public surface is the pieces that call is assembled from, for
|
|
65
|
+
when you are wiring a signer yourself rather than taking the whole client:
|
|
66
|
+
|
|
67
|
+
| Export | What it is |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `signCb(para, wallet, showSigningModal, customSignConfirmStep?)` | Builds the `(publicKey, signingInputs) => Promise<Uint8Array>` callback a `MidenClient` keystore or a React `SignerContext` wants. |
|
|
70
|
+
| `resolveEvmWallets(para, wallets)` | Narrows a wallet list to full EVM `Wallet` records. Read the rule below before skipping it. |
|
|
71
|
+
| `getUncompressedPublicKeyFromWallet(para, wallet)` | The wallet's uncompressed key, falling back to `para.issueJwt()` when the record carries none. Throws rather than returning `undefined`. |
|
|
72
|
+
| `evmPkToCommitment(uncompressedPublicKey)` | The Miden public-key commitment for that key. |
|
|
73
|
+
| types | `Opts`, `MidenAccountOpts`, `MidenAccountStorageMode`, `TxSummaryJson`, `CustomSignConfirmStep` |
|
|
74
|
+
|
|
75
|
+
The confirmation modals are internal: they are not exported, and you replace
|
|
76
|
+
them with `showSigningModal: false` plus your own `customSignConfirmStep`, not
|
|
77
|
+
by importing them.
|
|
78
|
+
|
|
79
|
+
## Rules that are easy to get wrong
|
|
80
|
+
|
|
81
|
+
**Resolve wallets through Para, not through `embedded.wallets`.** Para 3's
|
|
82
|
+
`useAccount().embedded.wallets` is `AvailableWallet[]` and omits `publicKey`.
|
|
83
|
+
Handing those records straight to the signing path costs an `issueJwt()` round
|
|
84
|
+
trip on every account bootstrap, and fails outright when the JWT has no entry
|
|
85
|
+
for the wallet. `resolveEvmWallets` prefers `para.getWalletsByType("EVM")`,
|
|
86
|
+
which returns full `Wallet` records, and falls back to filtering the list you
|
|
87
|
+
passed when the client does not expose it. `createParaMidenClient` already does
|
|
88
|
+
this for you.
|
|
89
|
+
|
|
90
|
+
**`storageMode: "private"` requires `accountSeed`.** Without one the call throws
|
|
91
|
+
before any client is built, because a private account that cannot be
|
|
92
|
+
regenerated from a seed is unrecoverable.
|
|
93
|
+
|
|
94
|
+
**A 0.15 account does not survive the upgrade.** `evmPkToCommitment` hashes the
|
|
95
|
+
affine point as Poseidon2 over 16 field elements - the x coordinate then the y
|
|
96
|
+
coordinate, each as eight 32-bit limbs, least significant limb first. 0.15
|
|
97
|
+
hashed a different preimage (nine felts packed from the 33-byte compressed SEC1
|
|
98
|
+
encoding), so the same EVM key yields a different account id and a different
|
|
99
|
+
commitment on 0.16. Treat it as a new account, not a migration.
|
|
100
|
+
|
|
101
|
+
**This path touches the DOM.** The account picker and the signing confirmation
|
|
102
|
+
are plain DOM overlays. They are guarded on `typeof document`, so on a server
|
|
103
|
+
the picker resolves to the first wallet and the signing prompt auto-approves.
|
|
104
|
+
Never run this flow server-side expecting a human in the loop. The picker is
|
|
105
|
+
also skipped when exactly one EVM wallet resolves.
|
|
106
|
+
|
|
107
|
+
**Para 3.18 needs bundler help.** `@getpara/react-core` lazily imports the
|
|
108
|
+
optional `@getpara/aa-*` account-abstraction connectors and the Solana and
|
|
109
|
+
Cosmos connectors. Vite's dependency pre-bundling resolves those specifiers
|
|
110
|
+
even though nothing calls them, so a build fails unless they are stubbed. The
|
|
111
|
+
`paraVitePlugin` exported from `@miden-sdk/para-react/vite` does exactly that;
|
|
112
|
+
the skill covers the non-Vite case.
|
|
113
|
+
|
|
114
|
+
## Going deeper
|
|
115
|
+
|
|
116
|
+
- The React surface documents itself at
|
|
117
|
+
`node_modules/@miden-sdk/para-react/AGENTS.md`.
|
|
118
|
+
- The client this wraps documents itself at
|
|
119
|
+
`node_modules/@miden-sdk/miden-sdk/AGENTS.md`, with narrative docs at
|
|
120
|
+
<https://docs.miden.xyz/builder/tools/clients/web-client/>.
|
|
121
|
+
- Para's own SDK documentation: <https://docs.getpara.com>.
|
|
122
|
+
- Breaking changes and migration notes, worth reading at upgrade time: the
|
|
123
|
+
`CHANGELOG.md` in [`0xMiden/web-sdk`](https://github.com/0xMiden/web-sdk).
|
|
124
|
+
- The type declarations shipped in `dist/` are authoritative for signatures.
|
|
125
|
+
When this guide and the types disagree, the types are right and this file is a
|
|
126
|
+
bug - please report it.
|
package/README.md
CHANGED
|
@@ -1,49 +1,52 @@
|
|
|
1
1
|
# @miden-sdk/para
|
|
2
2
|
|
|
3
|
-
[](https://github.com/0xMiden/
|
|
4
|
-
[](https://github.com/0xMiden/miden-para/actions/workflows/test.yml)
|
|
5
|
-
[](https://github.com/0xMiden/miden-para/actions/workflows/build.yml)
|
|
3
|
+
[](https://github.com/0xMiden/web-sdk/blob/main/LICENSE.md)
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
The Miden x Para integration: build a Miden account from a Para-managed EVM
|
|
6
|
+
wallet and sign Miden transactions through Para.
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- A Para API key. **Production deployments require a Para production API key**; use a non-prod key for local/dev.
|
|
8
|
+
For the React bindings see [`@miden-sdk/para-react`](https://www.npmjs.com/package/@miden-sdk/para-react),
|
|
9
|
+
which is where `ParaSignerProvider` and the hooks live. To scaffold a fresh Vite
|
|
10
|
+
`react-ts` app with the Miden and Para config already wired, use
|
|
11
|
+
[`@miden-sdk/create-para-react`](https://www.npmjs.com/package/@miden-sdk/create-para-react).
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
## Agent guidance
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
If you are an AI coding agent, read
|
|
16
|
+
`node_modules/@miden-sdk/para/AGENTS.md` and
|
|
17
|
+
`node_modules/@miden-sdk/para/skills/para-signer/SKILL.md` before writing code
|
|
18
|
+
against this package. They ship in this tarball, so they match the version you
|
|
19
|
+
have installed.
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
## Requirements
|
|
20
22
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
+
- Node.js >= 20.
|
|
24
|
+
- A Para API key. **Production deployments require a Para production API key**;
|
|
25
|
+
use a non-production key for local and development work.
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
## Installation
|
|
25
28
|
|
|
26
29
|
```bash
|
|
27
|
-
|
|
30
|
+
pnpm add @miden-sdk/para @miden-sdk/miden-sdk @getpara/web-sdk
|
|
28
31
|
```
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
## Peer dependencies
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
`@miden-sdk/para` expects these to be provided by the consuming app. Install
|
|
36
|
+
matching versions alongside it so no duplicate copy of the SDK is resolved:
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```
|
|
38
|
+
- `@miden-sdk/miden-sdk@^0.16.1`
|
|
39
|
+
- `@getpara/web-sdk@^3.18.0`
|
|
37
40
|
|
|
38
|
-
|
|
41
|
+
Para SDK 3.18 is required as of 0.16.1; the 2.x range no longer satisfies the
|
|
42
|
+
peer.
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
When creating a client with `storageMode` set to `private`, supply an
|
|
45
|
+
`accountSeed`. The initializer throws if it is missing, so that private accounts
|
|
46
|
+
stay recoverable.
|
|
43
47
|
|
|
44
|
-
##
|
|
48
|
+
## Contributing
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
4. (Optional) Inspect the packed artifact without publishing via `npm pack` and check `build/` for the resulting `miden-sdk-miden-para-<version>.tgz`.
|
|
50
|
+
This package is developed in the [`0xMiden/web-sdk`](https://github.com/0xMiden/web-sdk)
|
|
51
|
+
monorepo under `packages/para/core`, and is released from it. See that repo's
|
|
52
|
+
`CONTRIBUTING.md` and `AGENTS.md` for the build, test and release flow.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miden-sdk/para",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0-rc.1",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"description": "Miden x Para Integration",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"react": "^19.2.0",
|
|
30
30
|
"react-test-renderer": "^19.2.0",
|
|
31
31
|
"typescript": "^5.8.3",
|
|
32
|
-
"@miden-sdk/miden-sdk": "0.
|
|
32
|
+
"@miden-sdk/miden-sdk": "0.17.0-rc.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@getpara/web-sdk": "^3.18.0",
|
|
36
|
-
"@miden-sdk/miden-sdk": "^0.
|
|
36
|
+
"@miden-sdk/miden-sdk": "^0.17.0-rc.1"
|
|
37
37
|
},
|
|
38
38
|
"exports": {
|
|
39
39
|
".": {
|
|
@@ -50,7 +50,9 @@
|
|
|
50
50
|
"files": [
|
|
51
51
|
"dist",
|
|
52
52
|
"package.json",
|
|
53
|
-
"
|
|
53
|
+
"README.md",
|
|
54
|
+
"AGENTS.md",
|
|
55
|
+
"skills"
|
|
54
56
|
],
|
|
55
57
|
"main": "dist/cjs/index.js",
|
|
56
58
|
"module": "dist/esm/index.js",
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: para-signer
|
|
3
|
+
description: Wiring Para (getpara.com) wallets into a Miden app with @miden-sdk/para and @miden-sdk/para-react. Covers the two integration paths (ParaSignerProvider vs createParaMidenClient/useParaMiden), Para 3 EVM wallet resolution, the signing and account-commitment model, the bundler stubs Para 3.18 needs, and the errors each mistake produces. Use when adding Para authentication, debugging a Para-backed signer, or upgrading a Para integration from Para SDK 2.x.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Para Signer Integration
|
|
7
|
+
|
|
8
|
+
Generic signer material - why a signer provider wraps `MidenProvider`, the
|
|
9
|
+
unified `useSigner()` interface, writing a signer of your own - is in
|
|
10
|
+
`node_modules/@miden-sdk/miden-sdk/skills/signer-integration/SKILL.md`. This
|
|
11
|
+
skill is only the Para-specific half.
|
|
12
|
+
|
|
13
|
+
## The packages
|
|
14
|
+
|
|
15
|
+
| Package | Contains |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `@miden-sdk/para` | Framework-agnostic core: `createParaMidenClient`, `signCb`, `resolveEvmWallets`, `getUncompressedPublicKeyFromWallet`, `evmPkToCommitment`. |
|
|
18
|
+
| `@miden-sdk/para-react` | React: `ParaSignerProvider`, `useParaSigner`, `useParaMiden`, and `paraVitePlugin` on the `./vite` entry. |
|
|
19
|
+
| `@miden-sdk/create-para-react` | `npm create @miden-sdk/para-react@latest my-app`. |
|
|
20
|
+
|
|
21
|
+
As of 0.16.1 all three peer on Para SDK 3.18 (`@getpara/web-sdk` and
|
|
22
|
+
`@getpara/react-sdk-lite` at `^3.18.0`). The 2.x range is dropped and will not
|
|
23
|
+
satisfy the peer.
|
|
24
|
+
|
|
25
|
+
## Pick one path
|
|
26
|
+
|
|
27
|
+
**`ParaSignerProvider`** is the default for a React app. It publishes a
|
|
28
|
+
`SignerContext`, so every `@miden-sdk/react` hook signs through Para with no
|
|
29
|
+
further wiring, and `MidenProvider` manages the single client.
|
|
30
|
+
|
|
31
|
+
**`createParaMidenClient`** (or its hook wrapper `useParaMiden`) builds and
|
|
32
|
+
returns a `MidenClient` of its own. Use it in a non-React app, or when you are
|
|
33
|
+
driving the client directly and there is no `MidenProvider`.
|
|
34
|
+
|
|
35
|
+
Never both in one app: each owns a WASM-backed client, with its own store and
|
|
36
|
+
its own account bootstrap, and concurrent access to the WASM module crashes.
|
|
37
|
+
|
|
38
|
+
### Path A: ParaSignerProvider
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { ParaSignerProvider, useParaSigner } from "@miden-sdk/para-react";
|
|
42
|
+
import { MidenProvider, useSigner, useMiden } from "@miden-sdk/react";
|
|
43
|
+
|
|
44
|
+
<ParaSignerProvider apiKey={apiKey} environment="BETA" appName="My App">
|
|
45
|
+
<MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
46
|
+
<App />
|
|
47
|
+
</MidenProvider>
|
|
48
|
+
</ParaSignerProvider>;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Prop | Default | Notes |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `apiKey` | required | Para API key. Production deployments need a production key. |
|
|
54
|
+
| `environment` | required | `"BETA"`, `"PROD"`, `"SANDBOX"`, `"DEV"`, `"DEVELOPMENT"` or `"PRODUCTION"`. The last two are used directly when the Para build defines them, and fall back to `BETA` and `PROD` when it does not. |
|
|
55
|
+
| `appName` | `"Miden App"` | Shown in the Para modal. |
|
|
56
|
+
| `showSigningModal` | `true` | The built-in transaction confirmation overlay. |
|
|
57
|
+
| `customSignConfirmStep` | none | `(txSummaryJson) => Promise<unknown>`, run after the built-in modal and before Para signs. Throw to abort. |
|
|
58
|
+
| `queryClient` | internal | Pass yours to share one React Query client. |
|
|
59
|
+
| `paraProviderConfig` | none | Merged into `ParaProvider`: OAuth methods, external wallets, everything else Para exposes. |
|
|
60
|
+
| `customComponents` | none | Extra `AccountComponent`s, forwarded into `accountConfig`. |
|
|
61
|
+
| `importAccountId` | none | Import this account instead of building one. |
|
|
62
|
+
|
|
63
|
+
The provider renders `QueryClientProvider` and Para's `ParaProvider` itself and
|
|
64
|
+
imports `@getpara/react-sdk-lite/styles.css`. Do not wrap it with either again.
|
|
65
|
+
|
|
66
|
+
What it puts on the context: `name: "Para"`, `storeName: para_<walletId>` (so
|
|
67
|
+
two Para users on one browser do not share an IndexedDB store), a `signCb` bound
|
|
68
|
+
to the resolved wallet, and an `accountConfig` whose `publicKeyCommitment` is
|
|
69
|
+
the serialized commitment for that wallet's EVM key. **The storage mode is
|
|
70
|
+
always public.** There is no prop to make the signer's account private; use path
|
|
71
|
+
B with `storageMode: "private"` if you need that.
|
|
72
|
+
|
|
73
|
+
`connect()` opens the Para modal and `disconnect()` logs out of both the React
|
|
74
|
+
SDK and the Para client. `useParaSigner()` adds `{ para, wallet, isConnected }`
|
|
75
|
+
and throws outside the provider. `useModal` and `useLogout` are re-exported from
|
|
76
|
+
`@getpara/react-sdk-lite`.
|
|
77
|
+
|
|
78
|
+
Before the wallet connects, the provider publishes a deliberate
|
|
79
|
+
`isConnected: false` placeholder rather than `null`. That is what keeps
|
|
80
|
+
`MidenProvider` from building a local-keystore client - and touching WASM -
|
|
81
|
+
while the provider is still deriving the commitment. Do not "simplify" it to
|
|
82
|
+
`null`.
|
|
83
|
+
|
|
84
|
+
### Path B: createParaMidenClient
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { createParaMidenClient } from "@miden-sdk/para";
|
|
88
|
+
|
|
89
|
+
const { client, accountId } = await createParaMidenClient(
|
|
90
|
+
para, // ParaWeb
|
|
91
|
+
wallets, // session wallets; EVM entries are selected from these
|
|
92
|
+
{ endpoint: "https://rpc.testnet.miden.io", storageMode: "public" },
|
|
93
|
+
true, // showSigningModal
|
|
94
|
+
confirmTx // optional customSignConfirmStep
|
|
95
|
+
);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`Opts` fields: `endpoint` (the RPC URL - the field is not called `rpcUrl`),
|
|
99
|
+
`noteTransportUrl` (default `https://transport.miden.io`; `nodeTransportUrl` is
|
|
100
|
+
a deprecated alias), `seed` (client store seed), `accountSeed`, and the required
|
|
101
|
+
`storageMode` (`"public"` or `"private"`).
|
|
102
|
+
|
|
103
|
+
In React, `useParaMiden(nodeUrl, storageMode?, opts?, showSigningModal?, customSignConfirmStep?)`
|
|
104
|
+
wraps the same call under a Para `ParaProvider` ancestor and returns
|
|
105
|
+
`{ client, accountId, error, para, evmWallets, nodeUrl, opts }`. `client` is
|
|
106
|
+
`null` until the session resolves, it is held in a ref so re-renders do not
|
|
107
|
+
rebuild it, and setup failures land on `error` instead of throwing.
|
|
108
|
+
|
|
109
|
+
Both forms open DOM overlays: an account picker when more than one EVM wallet
|
|
110
|
+
resolves, and a confirmation per signature unless `showSigningModal` is `false`.
|
|
111
|
+
Both are guarded on `typeof document`, so server-side the picker silently
|
|
112
|
+
returns the first wallet and the signing prompt auto-approves. Do not run this
|
|
113
|
+
path on a server expecting a human in the loop.
|
|
114
|
+
|
|
115
|
+
## Resolve EVM wallets through Para, always
|
|
116
|
+
|
|
117
|
+
This is the single most common Para 3 defect. `useAccount().embedded.wallets`
|
|
118
|
+
is `AvailableWallet[]`: it has `id` and `type`, and it does **not** have
|
|
119
|
+
`publicKey`. Everything downstream needs the uncompressed public key, so a
|
|
120
|
+
record without one sends `getUncompressedPublicKeyFromWallet` down its
|
|
121
|
+
`para.issueJwt()` fallback, and that fails outright when the JWT carries no
|
|
122
|
+
entry for the wallet.
|
|
123
|
+
|
|
124
|
+
`resolveEvmWallets(para, wallets)` prefers `para.getWalletsByType("EVM")`, which
|
|
125
|
+
returns full `Wallet` records, intersects it with the list you passed, and falls
|
|
126
|
+
back to filtering that list when the client does not expose the method.
|
|
127
|
+
`createParaMidenClient` and `ParaSignerProvider` both call it. Call it yourself
|
|
128
|
+
before handing wallets to `signCb`.
|
|
129
|
+
|
|
130
|
+
## The signing and commitment model
|
|
131
|
+
|
|
132
|
+
`signCb(para, wallet, showSigningModal, customSignConfirmStep?)` returns the
|
|
133
|
+
callback a `MidenClient` keystore or a `SignerContext` wants. Per signature it:
|
|
134
|
+
|
|
135
|
+
1. deserializes the `SigningInputs` and takes `inputs.toCommitment()`;
|
|
136
|
+
2. keccak-256 hashes that commitment;
|
|
137
|
+
3. renders the transaction summary for confirmation, then runs
|
|
138
|
+
`customSignConfirmStep`;
|
|
139
|
+
4. calls `para.signMessage({ walletId, messageBase64 })`;
|
|
140
|
+
5. prefixes the signature with the ECDSA auth-scheme byte and returns the bytes
|
|
141
|
+
Miden expects.
|
|
142
|
+
|
|
143
|
+
Use it as-is. Hand-rolling the hash or the serialization is how "invalid
|
|
144
|
+
signature" bugs start.
|
|
145
|
+
|
|
146
|
+
The account's auth component commits to the EVM key through
|
|
147
|
+
`evmPkToCommitment`, which hashes the affine point as Poseidon2 over 16 field
|
|
148
|
+
elements: the x coordinate then the y coordinate, each as eight 32-bit limbs,
|
|
149
|
+
least significant limb first.
|
|
150
|
+
|
|
151
|
+
> **Upgrade trap.** 0.15 hashed a different preimage - nine felts packed from
|
|
152
|
+
> the 33-byte compressed SEC1 encoding. The same Para wallet therefore derives a
|
|
153
|
+
> different commitment, and a different account id, on 0.16. There is no
|
|
154
|
+
> migration: it is a new account.
|
|
155
|
+
|
|
156
|
+
Account bootstrap, for a public account, tries `client.accounts.import(account)`
|
|
157
|
+
first and only inserts a fresh one when nothing was on chain. That is what makes
|
|
158
|
+
a second login on a new device pick the existing account up rather than
|
|
159
|
+
submitting a zero-nonce duplicate. A private account cannot be recovered that
|
|
160
|
+
way, which is why `storageMode: "private"` without `accountSeed` throws before
|
|
161
|
+
any client is built.
|
|
162
|
+
|
|
163
|
+
## Bundler setup
|
|
164
|
+
|
|
165
|
+
`@getpara/react-core` lazily imports optional connectors that almost nobody
|
|
166
|
+
installs: the ten `@getpara/aa-*` account-abstraction packages, plus
|
|
167
|
+
`@getpara/solana-wallet-connectors` and `@getpara/cosmos-wallet-connectors`.
|
|
168
|
+
Lazy or not, a bundler still resolves the specifier, so the build fails on
|
|
169
|
+
packages your app never calls.
|
|
170
|
+
|
|
171
|
+
On Vite, use the plugin:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
// vite.config.ts
|
|
175
|
+
import { paraVitePlugin } from "@miden-sdk/para-react/vite";
|
|
176
|
+
import { midenVitePlugin } from "@miden-sdk/vite-plugin";
|
|
177
|
+
|
|
178
|
+
export default defineConfig({
|
|
179
|
+
plugins: [react(), midenVitePlugin(), paraVitePlugin()],
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`paraVitePlugin()` returns an array of plugins (Vite flattens it) that stubs
|
|
184
|
+
those twelve packages at both the esbuild pre-bundling layer and Vite's own
|
|
185
|
+
resolver, dedupes `@getpara/web-sdk` and `@getpara/react-sdk-lite`, and adds
|
|
186
|
+
Node polyfills for `buffer`, `crypto`, `stream` and `util`. Override that list
|
|
187
|
+
with `paraVitePlugin({ polyfills: [...] })`. The polyfills come from
|
|
188
|
+
`vite-plugin-node-polyfills`, an optional peer resolved from your project's
|
|
189
|
+
`node_modules`: without it the plugin warns and returns the stubs alone.
|
|
190
|
+
|
|
191
|
+
On another bundler, reproduce the three requirements by hand: resolve those
|
|
192
|
+
twelve specifiers to an empty module, provide the four Node polyfills, and force
|
|
193
|
+
a single copy of each `@getpara/*` package.
|
|
194
|
+
|
|
195
|
+
## What each failure looks like
|
|
196
|
+
|
|
197
|
+
| Message | Cause |
|
|
198
|
+
| --- | --- |
|
|
199
|
+
| `No EVM wallets provided` | The session has no EVM wallet, or a non-EVM list was passed. Check `type === "EVM"` and that Para finished connecting. |
|
|
200
|
+
| `Got invalid jwt token`, `Wallet Not Found in jwt data`, `Wallet in jwt data has no public key` | The wallet record had no `publicKey` and the JWT fallback could not supply one. Resolve wallets through `getWalletsByType("EVM")`. |
|
|
201
|
+
| `accountSeed is required when using private storage mode` | `storageMode: "private"` with no `accountSeed`. |
|
|
202
|
+
| `User cancelled signing` | The confirmation modal was declined. Expected, not a bug. |
|
|
203
|
+
| `useParaSigner must be used within ParaSignerProvider` | The hook is mounted outside the provider. |
|
|
204
|
+
| A build error naming `@getpara/aa-<something>` | The connector stubs are missing. See "Bundler setup". |
|
|
205
|
+
| The app connects to Para but the signer stays disconnected | `ParaSignerProvider` logs `Failed to build Para signer context:` and falls back to the disconnected context. The console error is the real one; it is usually public-key resolution. |
|
|
206
|
+
| `Output note <id> carries no asset data` | The transaction summary could not be rendered. Deliberate: the modal would otherwise print "Assets: None" for assets that are merely unknown. |
|
|
207
|
+
|
|
208
|
+
## Environment
|
|
209
|
+
|
|
210
|
+
`VITE_PARA_API_KEY` is the convention across the examples and the scaffolded
|
|
211
|
+
template, read through `import.meta.env`. Use a non-production Para key for
|
|
212
|
+
local and dev work; production deployments need a production key.
|