@miden-sdk/use-miden-para-react 0.10.10 → 0.13.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/README.md +3 -3
- package/dist/index.d.mts +70 -3
- package/dist/index.d.ts +70 -3
- package/dist/index.js +206 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +213 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -6
- package/src/ParaSignerProvider.tsx +323 -0
- package/src/index.ts +8 -0
- package/src/useParaMiden.ts +2 -2
package/README.md
CHANGED
|
@@ -12,15 +12,15 @@ npm install @miden-sdk/use-miden-para-react
|
|
|
12
12
|
|
|
13
13
|
`@miden-sdk/use-miden-para-react` expects these packages to be provided by the consuming app. Install matching versions alongside this package to avoid duplicate copies:
|
|
14
14
|
|
|
15
|
-
- `@
|
|
15
|
+
- `@miden-sdk/miden-sdk@^0.13.0`
|
|
16
16
|
- `@getpara/react-sdk-lite@^2.2.0`
|
|
17
|
-
- `@miden-sdk/miden-para@^0.
|
|
17
|
+
- `@miden-sdk/miden-para@^0.13.0`
|
|
18
18
|
- `react@^18.0.0 || ^19.0.0`
|
|
19
19
|
|
|
20
20
|
Example install:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
yarn add @miden-sdk/use-miden-para-react @
|
|
23
|
+
yarn add @miden-sdk/use-miden-para-react @miden-sdk/miden-sdk@^0.13.0 @getpara/react-sdk-lite@^2.2.0 @miden-sdk/miden-para@^0.13.0 react@^18.0.0
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
## Usage
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import * as _getpara_react_sdk_lite from '@getpara/react-sdk-lite';
|
|
2
|
-
import
|
|
2
|
+
import { ParaProviderProps } from '@getpara/react-sdk-lite';
|
|
3
|
+
export { useLogout, useModal } from '@getpara/react-sdk-lite';
|
|
4
|
+
import * as _miden_sdk_miden_sdk from '@miden-sdk/miden-sdk';
|
|
3
5
|
import { MidenAccountStorageMode, Opts, CustomSignConfirmStep } from '@miden-sdk/miden-para';
|
|
6
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
7
|
+
import { ReactNode } from 'react';
|
|
8
|
+
import { ParaWeb, Wallet } from '@getpara/web-sdk';
|
|
9
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
4
10
|
|
|
5
11
|
/**
|
|
6
12
|
* React hook that converts Para React SDK context into a ready-to-use Miden WebClient.
|
|
@@ -17,7 +23,7 @@ import { MidenAccountStorageMode, Opts, CustomSignConfirmStep } from '@miden-sdk
|
|
|
17
23
|
* - customSignConfirmStep: optional callback for custom transaction confirmation flows
|
|
18
24
|
*/
|
|
19
25
|
declare function useParaMiden(nodeUrl: string, storageMode?: MidenAccountStorageMode, opts?: Omit<Opts, 'endpoint' | 'type' | 'storageMode'>, showSigningModal?: boolean, customSignConfirmStep?: CustomSignConfirmStep): {
|
|
20
|
-
client:
|
|
26
|
+
client: _miden_sdk_miden_sdk.WebClient | null;
|
|
21
27
|
accountId: string;
|
|
22
28
|
para: _getpara_react_sdk_lite.default | undefined;
|
|
23
29
|
evmWallets: _getpara_react_sdk_lite.AvailableWallet[] | undefined;
|
|
@@ -25,4 +31,65 @@ declare function useParaMiden(nodeUrl: string, storageMode?: MidenAccountStorage
|
|
|
25
31
|
opts: Omit<Opts, "type" | "endpoint" | "storageMode">;
|
|
26
32
|
};
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
/** Environment string values accepted by ParaSignerProvider */
|
|
35
|
+
type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT' | 'PRODUCTION';
|
|
36
|
+
interface ParaSignerProviderProps {
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
/** Para API key */
|
|
39
|
+
apiKey: string;
|
|
40
|
+
/** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */
|
|
41
|
+
environment: ParaEnvironment;
|
|
42
|
+
/** App name displayed in Para modal */
|
|
43
|
+
appName?: string;
|
|
44
|
+
/** Whether to show the signing modal for transaction confirmation */
|
|
45
|
+
showSigningModal?: boolean;
|
|
46
|
+
/** Custom sign confirmation step callback */
|
|
47
|
+
customSignConfirmStep?: CustomSignConfirmStep;
|
|
48
|
+
/**
|
|
49
|
+
* Optional custom QueryClient instance for React Query.
|
|
50
|
+
* If not provided, a default instance is used internally.
|
|
51
|
+
*/
|
|
52
|
+
queryClient?: QueryClient;
|
|
53
|
+
/**
|
|
54
|
+
* Advanced: Additional config to pass to ParaProvider.
|
|
55
|
+
* Use this for customizing OAuth methods, external wallets, etc.
|
|
56
|
+
*/
|
|
57
|
+
paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Para-specific extras exposed via useParaSigner hook.
|
|
61
|
+
*/
|
|
62
|
+
interface ParaSignerExtras {
|
|
63
|
+
/** Para client instance */
|
|
64
|
+
para: ParaWeb;
|
|
65
|
+
/** Connected wallet (null if not connected) */
|
|
66
|
+
wallet: Wallet | null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* ParaSignerProvider wraps MidenProvider to enable Para wallet signing.
|
|
70
|
+
* Includes ParaProvider internally, so you don't need to wrap with it separately.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* <ParaSignerProvider apiKey="your-api-key" environment="BETA" appName="My App">
|
|
75
|
+
* <MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
76
|
+
* <App />
|
|
77
|
+
* </MidenProvider>
|
|
78
|
+
* </ParaSignerProvider>
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare function ParaSignerProvider({ children, apiKey, environment, appName, showSigningModal, customSignConfirmStep, queryClient, paraProviderConfig, }: ParaSignerProviderProps): react_jsx_runtime.JSX.Element;
|
|
82
|
+
/**
|
|
83
|
+
* Hook for Para-specific extras beyond the unified useSigner interface.
|
|
84
|
+
* Use this to access the Para client or wallet details directly.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```tsx
|
|
88
|
+
* const { para, wallet, isConnected } = useParaSigner();
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare function useParaSigner(): ParaSignerExtras & {
|
|
92
|
+
isConnected: boolean;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export { type ParaSignerExtras, ParaSignerProvider, type ParaSignerProviderProps, useParaMiden, useParaSigner };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import * as _getpara_react_sdk_lite from '@getpara/react-sdk-lite';
|
|
2
|
-
import
|
|
2
|
+
import { ParaProviderProps } from '@getpara/react-sdk-lite';
|
|
3
|
+
export { useLogout, useModal } from '@getpara/react-sdk-lite';
|
|
4
|
+
import * as _miden_sdk_miden_sdk from '@miden-sdk/miden-sdk';
|
|
3
5
|
import { MidenAccountStorageMode, Opts, CustomSignConfirmStep } from '@miden-sdk/miden-para';
|
|
6
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
7
|
+
import { ReactNode } from 'react';
|
|
8
|
+
import { ParaWeb, Wallet } from '@getpara/web-sdk';
|
|
9
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
4
10
|
|
|
5
11
|
/**
|
|
6
12
|
* React hook that converts Para React SDK context into a ready-to-use Miden WebClient.
|
|
@@ -17,7 +23,7 @@ import { MidenAccountStorageMode, Opts, CustomSignConfirmStep } from '@miden-sdk
|
|
|
17
23
|
* - customSignConfirmStep: optional callback for custom transaction confirmation flows
|
|
18
24
|
*/
|
|
19
25
|
declare function useParaMiden(nodeUrl: string, storageMode?: MidenAccountStorageMode, opts?: Omit<Opts, 'endpoint' | 'type' | 'storageMode'>, showSigningModal?: boolean, customSignConfirmStep?: CustomSignConfirmStep): {
|
|
20
|
-
client:
|
|
26
|
+
client: _miden_sdk_miden_sdk.WebClient | null;
|
|
21
27
|
accountId: string;
|
|
22
28
|
para: _getpara_react_sdk_lite.default | undefined;
|
|
23
29
|
evmWallets: _getpara_react_sdk_lite.AvailableWallet[] | undefined;
|
|
@@ -25,4 +31,65 @@ declare function useParaMiden(nodeUrl: string, storageMode?: MidenAccountStorage
|
|
|
25
31
|
opts: Omit<Opts, "type" | "endpoint" | "storageMode">;
|
|
26
32
|
};
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
/** Environment string values accepted by ParaSignerProvider */
|
|
35
|
+
type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT' | 'PRODUCTION';
|
|
36
|
+
interface ParaSignerProviderProps {
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
/** Para API key */
|
|
39
|
+
apiKey: string;
|
|
40
|
+
/** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */
|
|
41
|
+
environment: ParaEnvironment;
|
|
42
|
+
/** App name displayed in Para modal */
|
|
43
|
+
appName?: string;
|
|
44
|
+
/** Whether to show the signing modal for transaction confirmation */
|
|
45
|
+
showSigningModal?: boolean;
|
|
46
|
+
/** Custom sign confirmation step callback */
|
|
47
|
+
customSignConfirmStep?: CustomSignConfirmStep;
|
|
48
|
+
/**
|
|
49
|
+
* Optional custom QueryClient instance for React Query.
|
|
50
|
+
* If not provided, a default instance is used internally.
|
|
51
|
+
*/
|
|
52
|
+
queryClient?: QueryClient;
|
|
53
|
+
/**
|
|
54
|
+
* Advanced: Additional config to pass to ParaProvider.
|
|
55
|
+
* Use this for customizing OAuth methods, external wallets, etc.
|
|
56
|
+
*/
|
|
57
|
+
paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Para-specific extras exposed via useParaSigner hook.
|
|
61
|
+
*/
|
|
62
|
+
interface ParaSignerExtras {
|
|
63
|
+
/** Para client instance */
|
|
64
|
+
para: ParaWeb;
|
|
65
|
+
/** Connected wallet (null if not connected) */
|
|
66
|
+
wallet: Wallet | null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* ParaSignerProvider wraps MidenProvider to enable Para wallet signing.
|
|
70
|
+
* Includes ParaProvider internally, so you don't need to wrap with it separately.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* <ParaSignerProvider apiKey="your-api-key" environment="BETA" appName="My App">
|
|
75
|
+
* <MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
76
|
+
* <App />
|
|
77
|
+
* </MidenProvider>
|
|
78
|
+
* </ParaSignerProvider>
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare function ParaSignerProvider({ children, apiKey, environment, appName, showSigningModal, customSignConfirmStep, queryClient, paraProviderConfig, }: ParaSignerProviderProps): react_jsx_runtime.JSX.Element;
|
|
82
|
+
/**
|
|
83
|
+
* Hook for Para-specific extras beyond the unified useSigner interface.
|
|
84
|
+
* Use this to access the Para client or wallet details directly.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```tsx
|
|
88
|
+
* const { para, wallet, isConnected } = useParaSigner();
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare function useParaSigner(): ParaSignerExtras & {
|
|
92
|
+
isConnected: boolean;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export { type ParaSignerExtras, ParaSignerProvider, type ParaSignerProviderProps, useParaMiden, useParaSigner };
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
|
|
33
|
+
ParaSignerProvider: () => ParaSignerProvider,
|
|
34
|
+
useLogout: () => import_react_sdk_lite3.useLogout,
|
|
35
|
+
useModal: () => import_react_sdk_lite3.useModal,
|
|
36
|
+
useParaMiden: () => useParaMiden,
|
|
37
|
+
useParaSigner: () => useParaSigner
|
|
34
38
|
});
|
|
35
39
|
module.exports = __toCommonJS(index_exports);
|
|
36
40
|
|
|
@@ -59,7 +63,7 @@ function useParaMiden(nodeUrl, storageMode = "public", opts = {}, showSigningMod
|
|
|
59
63
|
if (!isConnected || !para || !((_a = embedded.wallets) == null ? void 0 : _a.length) || clientRef.current) {
|
|
60
64
|
return;
|
|
61
65
|
}
|
|
62
|
-
const { AccountType } = await import("@
|
|
66
|
+
const { AccountType } = await import("@miden-sdk/miden-sdk");
|
|
63
67
|
const { client: midenParaClient, accountId: aId } = await (0, import_miden_para.createParaMidenClient)(
|
|
64
68
|
para,
|
|
65
69
|
evmWallets,
|
|
@@ -99,8 +103,207 @@ function useParaMiden(nodeUrl, storageMode = "public", opts = {}, showSigningMod
|
|
|
99
103
|
opts
|
|
100
104
|
};
|
|
101
105
|
}
|
|
106
|
+
|
|
107
|
+
// src/ParaSignerProvider.tsx
|
|
108
|
+
var import_react2 = require("react");
|
|
109
|
+
var import_web_sdk = require("@getpara/web-sdk");
|
|
110
|
+
var import_react_sdk_lite2 = require("@getpara/react-sdk-lite");
|
|
111
|
+
var import_react_query = require("@tanstack/react-query");
|
|
112
|
+
var import_react3 = require("@miden-sdk/react");
|
|
113
|
+
var import_miden_para2 = require("@miden-sdk/miden-para");
|
|
114
|
+
var import_miden_para3 = require("@miden-sdk/miden-para");
|
|
115
|
+
var import_react_sdk_lite3 = require("@getpara/react-sdk-lite");
|
|
116
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
117
|
+
var defaultQueryClient = new import_react_query.QueryClient();
|
|
118
|
+
function getEnvironmentValue(env) {
|
|
119
|
+
const normalizedEnv = env === "DEVELOPMENT" ? "BETA" : env === "PRODUCTION" ? "PROD" : env;
|
|
120
|
+
if (import_web_sdk.Environment && typeof import_web_sdk.Environment === "object") {
|
|
121
|
+
const value = import_web_sdk.Environment[normalizedEnv];
|
|
122
|
+
if (value !== void 0) return value;
|
|
123
|
+
}
|
|
124
|
+
return normalizedEnv;
|
|
125
|
+
}
|
|
126
|
+
var ParaSignerExtrasContext = (0, import_react2.createContext)(null);
|
|
127
|
+
function ParaSignerProvider({
|
|
128
|
+
children,
|
|
129
|
+
apiKey,
|
|
130
|
+
environment,
|
|
131
|
+
appName = "Miden App",
|
|
132
|
+
showSigningModal = true,
|
|
133
|
+
customSignConfirmStep,
|
|
134
|
+
queryClient,
|
|
135
|
+
paraProviderConfig
|
|
136
|
+
}) {
|
|
137
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query.QueryClientProvider, { client: queryClient != null ? queryClient : defaultQueryClient, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
138
|
+
import_react_sdk_lite2.ParaProvider,
|
|
139
|
+
{
|
|
140
|
+
paraClientConfig: {
|
|
141
|
+
env: getEnvironmentValue(environment),
|
|
142
|
+
apiKey
|
|
143
|
+
},
|
|
144
|
+
config: { appName },
|
|
145
|
+
...paraProviderConfig,
|
|
146
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
147
|
+
ParaSignerProviderInner,
|
|
148
|
+
{
|
|
149
|
+
showSigningModal,
|
|
150
|
+
customSignConfirmStep,
|
|
151
|
+
children
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
) });
|
|
156
|
+
}
|
|
157
|
+
function ParaSignerProviderInner({
|
|
158
|
+
children,
|
|
159
|
+
showSigningModal = true,
|
|
160
|
+
customSignConfirmStep
|
|
161
|
+
}) {
|
|
162
|
+
const { openModal } = (0, import_react_sdk_lite2.useModal)();
|
|
163
|
+
const { logoutAsync } = (0, import_react_sdk_lite2.useLogout)();
|
|
164
|
+
const openModalRef = (0, import_react2.useRef)(openModal);
|
|
165
|
+
const logoutAsyncRef = (0, import_react2.useRef)(logoutAsync);
|
|
166
|
+
(0, import_react2.useEffect)(() => {
|
|
167
|
+
openModalRef.current = openModal;
|
|
168
|
+
}, [openModal]);
|
|
169
|
+
(0, import_react2.useEffect)(() => {
|
|
170
|
+
logoutAsyncRef.current = logoutAsync;
|
|
171
|
+
}, [logoutAsync]);
|
|
172
|
+
const para = (0, import_react_sdk_lite2.useClient)();
|
|
173
|
+
const paraRef = (0, import_react2.useRef)(para);
|
|
174
|
+
(0, import_react2.useEffect)(() => {
|
|
175
|
+
paraRef.current = para;
|
|
176
|
+
}, [para]);
|
|
177
|
+
const showSigningModalRef = (0, import_react2.useRef)(showSigningModal);
|
|
178
|
+
const customSignConfirmStepRef = (0, import_react2.useRef)(customSignConfirmStep);
|
|
179
|
+
(0, import_react2.useEffect)(() => {
|
|
180
|
+
showSigningModalRef.current = showSigningModal;
|
|
181
|
+
}, [showSigningModal]);
|
|
182
|
+
(0, import_react2.useEffect)(() => {
|
|
183
|
+
customSignConfirmStepRef.current = customSignConfirmStep;
|
|
184
|
+
}, [customSignConfirmStep]);
|
|
185
|
+
const [wallet, setWallet] = (0, import_react2.useState)(null);
|
|
186
|
+
const [isConnected, setIsConnected] = (0, import_react2.useState)(false);
|
|
187
|
+
(0, import_react2.useEffect)(() => {
|
|
188
|
+
let cancelled = false;
|
|
189
|
+
async function checkConnection() {
|
|
190
|
+
try {
|
|
191
|
+
const isLoggedIn = await paraRef.current.isFullyLoggedIn();
|
|
192
|
+
if (!isLoggedIn || cancelled) {
|
|
193
|
+
setIsConnected(false);
|
|
194
|
+
setWallet(null);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const wallets = Object.values(await paraRef.current.getWallets());
|
|
198
|
+
const evmWallets = wallets.filter((w) => w.type === "EVM");
|
|
199
|
+
if (evmWallets.length > 0 && !cancelled) {
|
|
200
|
+
setWallet((prev) => (prev == null ? void 0 : prev.id) === evmWallets[0].id ? prev : evmWallets[0]);
|
|
201
|
+
setIsConnected(true);
|
|
202
|
+
} else if (!cancelled) {
|
|
203
|
+
setIsConnected(false);
|
|
204
|
+
setWallet(null);
|
|
205
|
+
}
|
|
206
|
+
} catch {
|
|
207
|
+
if (!cancelled) {
|
|
208
|
+
setIsConnected(false);
|
|
209
|
+
setWallet(null);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
checkConnection();
|
|
214
|
+
const interval = setInterval(checkConnection, 2e3);
|
|
215
|
+
return () => {
|
|
216
|
+
cancelled = true;
|
|
217
|
+
clearInterval(interval);
|
|
218
|
+
};
|
|
219
|
+
}, []);
|
|
220
|
+
const connect = (0, import_react2.useCallback)(async () => {
|
|
221
|
+
openModalRef.current();
|
|
222
|
+
}, []);
|
|
223
|
+
const disconnect = (0, import_react2.useCallback)(async () => {
|
|
224
|
+
await logoutAsyncRef.current();
|
|
225
|
+
await paraRef.current.logout();
|
|
226
|
+
setIsConnected(false);
|
|
227
|
+
setWallet(null);
|
|
228
|
+
}, []);
|
|
229
|
+
const disconnectedCtx = (0, import_react2.useRef)({
|
|
230
|
+
signCb: async () => {
|
|
231
|
+
throw new Error("Para wallet not connected");
|
|
232
|
+
},
|
|
233
|
+
accountConfig: null,
|
|
234
|
+
storeName: "",
|
|
235
|
+
name: "Para",
|
|
236
|
+
isConnected: false,
|
|
237
|
+
connect,
|
|
238
|
+
disconnect
|
|
239
|
+
});
|
|
240
|
+
const [signerContext, setSignerContext] = (0, import_react2.useState)(
|
|
241
|
+
disconnectedCtx.current
|
|
242
|
+
);
|
|
243
|
+
(0, import_react2.useEffect)(() => {
|
|
244
|
+
let cancelled = false;
|
|
245
|
+
async function buildContext() {
|
|
246
|
+
if (!isConnected || !wallet) {
|
|
247
|
+
setSignerContext(disconnectedCtx.current);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
const p = paraRef.current;
|
|
252
|
+
const publicKey = await (0, import_miden_para3.getUncompressedPublicKeyFromWallet)(p, wallet);
|
|
253
|
+
if (!publicKey) throw new Error("Failed to get public key from wallet");
|
|
254
|
+
const commitment = await (0, import_miden_para3.evmPkToCommitment)(publicKey);
|
|
255
|
+
const commitmentBytes = commitment.serialize();
|
|
256
|
+
const signCallback = (0, import_miden_para2.signCb)(
|
|
257
|
+
p,
|
|
258
|
+
wallet,
|
|
259
|
+
showSigningModalRef.current,
|
|
260
|
+
customSignConfirmStepRef.current
|
|
261
|
+
);
|
|
262
|
+
if (!cancelled) {
|
|
263
|
+
const { AccountStorageMode } = await import("@miden-sdk/miden-sdk");
|
|
264
|
+
setSignerContext({
|
|
265
|
+
signCb: signCallback,
|
|
266
|
+
accountConfig: {
|
|
267
|
+
publicKeyCommitment: commitmentBytes,
|
|
268
|
+
accountType: "RegularAccountImmutableCode",
|
|
269
|
+
storageMode: AccountStorageMode.public()
|
|
270
|
+
},
|
|
271
|
+
storeName: `para_${wallet.id}`,
|
|
272
|
+
name: "Para",
|
|
273
|
+
isConnected: true,
|
|
274
|
+
connect,
|
|
275
|
+
disconnect
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
console.error("Failed to build Para signer context:", error);
|
|
280
|
+
if (!cancelled) {
|
|
281
|
+
setSignerContext(disconnectedCtx.current);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
buildContext();
|
|
286
|
+
return () => {
|
|
287
|
+
cancelled = true;
|
|
288
|
+
};
|
|
289
|
+
}, [isConnected, wallet, connect, disconnect]);
|
|
290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ParaSignerExtrasContext.Provider, { value: { para, wallet }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react3.SignerContext.Provider, { value: signerContext, children }) });
|
|
291
|
+
}
|
|
292
|
+
function useParaSigner() {
|
|
293
|
+
var _a;
|
|
294
|
+
const extras = (0, import_react2.useContext)(ParaSignerExtrasContext);
|
|
295
|
+
const signer = (0, import_react2.useContext)(import_react3.SignerContext);
|
|
296
|
+
if (!extras) {
|
|
297
|
+
throw new Error("useParaSigner must be used within ParaSignerProvider");
|
|
298
|
+
}
|
|
299
|
+
return { ...extras, isConnected: (_a = signer == null ? void 0 : signer.isConnected) != null ? _a : false };
|
|
300
|
+
}
|
|
102
301
|
// Annotate the CommonJS export names for ESM import in node:
|
|
103
302
|
0 && (module.exports = {
|
|
104
|
-
|
|
303
|
+
ParaSignerProvider,
|
|
304
|
+
useLogout,
|
|
305
|
+
useModal,
|
|
306
|
+
useParaMiden,
|
|
307
|
+
useParaSigner
|
|
105
308
|
});
|
|
106
309
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/useParaMiden.ts"],"sourcesContent":["export { useParaMiden } from './useParaMiden';\n","'use client';\n\nimport { useClient, useAccount, type Wallet } from '@getpara/react-sdk-lite';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createParaMidenClient,\n type Opts,\n type MidenAccountStorageMode,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\n\n/**\n * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.\n * Spawns the client once a Para session with at least one EVM wallet is active.\n *\n * Returns:\n * - client: WebClient instance backed by the active Para session (or null while loading)\n * - accountId: Miden account id derived for the selected EVM wallet\n * - para: Para client instance from context\n * - evmWallets: filtered list of Para wallets with type === 'EVM'\n * - nodeUrl: Miden node endpoint used for the client\n * - opts: forwarded options used when creating the client\n * - showSigningModal: toggles the built-in signing modal\n * - customSignConfirmStep: optional callback for custom transaction confirmation flows\n */\nexport function useParaMiden(\n nodeUrl: string,\n storageMode: MidenAccountStorageMode = 'public',\n opts: Omit<Opts, 'endpoint' | 'type' | 'storageMode'> = {},\n showSigningModal: boolean = true,\n customSignConfirmStep?: CustomSignConfirmStep\n) {\n const para = useClient();\n const { isConnected, embedded } = useAccount();\n const clientRef = useRef<import('@demox-labs/miden-sdk').WebClient | null>(\n null\n );\n const [accountId, setAccountId] = useState<string>('');\n\n const evmWallets = useMemo(\n () => embedded.wallets?.filter((wallet) => wallet.type === 'EVM'),\n [embedded.wallets]\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function setupClient() {\n if (\n !isConnected ||\n !para ||\n !embedded.wallets?.length ||\n clientRef.current\n ) {\n return;\n }\n\n const { AccountType } = await import('@demox-labs/miden-sdk');\n\n const { client: midenParaClient, accountId: aId } =\n await createParaMidenClient(\n para,\n evmWallets as Wallet[],\n {\n ...opts,\n endpoint: nodeUrl,\n type: AccountType.RegularAccountImmutableCode,\n storageMode,\n },\n showSigningModal,\n customSignConfirmStep\n );\n\n if (cancelled) {\n return;\n }\n\n clientRef.current = midenParaClient;\n setAccountId(aId);\n }\n\n setupClient();\n\n return () => {\n cancelled = true;\n };\n }, [\n isConnected,\n evmWallets,\n para,\n nodeUrl,\n showSigningModal,\n customSignConfirmStep,\n ]);\n\n return {\n client: clientRef.current,\n accountId,\n para,\n evmWallets,\n nodeUrl,\n opts,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,4BAAmD;AACnD,mBAAqD;AACrD,wBAKO;AAgBA,SAAS,aACd,SACA,cAAuC,UACvC,OAAwD,CAAC,GACzD,mBAA4B,MAC5B,uBACA;AACA,QAAM,WAAO,iCAAU;AACvB,QAAM,EAAE,aAAa,SAAS,QAAI,kCAAW;AAC7C,QAAM,gBAAY;AAAA,IAChB;AAAA,EACF;AACA,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAiB,EAAE;AAErD,QAAM,iBAAa;AAAA,IACjB,MAAG;AAxCP;AAwCU,4BAAS,YAAT,mBAAkB,OAAO,CAAC,WAAW,OAAO,SAAS;AAAA;AAAA,IAC3D,CAAC,SAAS,OAAO;AAAA,EACnB;AAEA,8BAAU,MAAM;AACd,QAAI,YAAY;AAEhB,mBAAe,cAAc;AA/CjC;AAgDM,UACE,CAAC,eACD,CAAC,QACD,GAAC,cAAS,YAAT,mBAAkB,WACnB,UAAU,SACV;AACA;AAAA,MACF;AAEA,YAAM,EAAE,YAAY,IAAI,MAAM,OAAO,uBAAuB;AAE5D,YAAM,EAAE,QAAQ,iBAAiB,WAAW,IAAI,IAC9C,UAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,UACE,GAAG;AAAA,UACH,UAAU;AAAA,UACV,MAAM,YAAY;AAAA,UAClB;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEF,UAAI,WAAW;AACb;AAAA,MACF;AAEA,gBAAU,UAAU;AACpB,mBAAa,GAAG;AAAA,IAClB;AAEA,gBAAY;AAEZ,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,QAAQ,UAAU;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/useParaMiden.ts","../src/ParaSignerProvider.tsx"],"sourcesContent":["export { useParaMiden } from './useParaMiden';\nexport {\n ParaSignerProvider,\n useParaSigner,\n useModal,\n useLogout,\n type ParaSignerProviderProps,\n type ParaSignerExtras,\n} from './ParaSignerProvider';\n","'use client';\n\nimport { useClient, useAccount, type Wallet } from '@getpara/react-sdk-lite';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createParaMidenClient,\n type Opts,\n type MidenAccountStorageMode,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\n\n/**\n * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.\n * Spawns the client once a Para session with at least one EVM wallet is active.\n *\n * Returns:\n * - client: WebClient instance backed by the active Para session (or null while loading)\n * - accountId: Miden account id derived for the selected EVM wallet\n * - para: Para client instance from context\n * - evmWallets: filtered list of Para wallets with type === 'EVM'\n * - nodeUrl: Miden node endpoint used for the client\n * - opts: forwarded options used when creating the client\n * - showSigningModal: toggles the built-in signing modal\n * - customSignConfirmStep: optional callback for custom transaction confirmation flows\n */\nexport function useParaMiden(\n nodeUrl: string,\n storageMode: MidenAccountStorageMode = 'public',\n opts: Omit<Opts, 'endpoint' | 'type' | 'storageMode'> = {},\n showSigningModal: boolean = true,\n customSignConfirmStep?: CustomSignConfirmStep\n) {\n const para = useClient();\n const { isConnected, embedded } = useAccount();\n const clientRef = useRef<import('@miden-sdk/miden-sdk').WebClient | null>(\n null\n );\n const [accountId, setAccountId] = useState<string>('');\n\n const evmWallets = useMemo(\n () => embedded.wallets?.filter((wallet) => wallet.type === 'EVM'),\n [embedded.wallets]\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function setupClient() {\n if (\n !isConnected ||\n !para ||\n !embedded.wallets?.length ||\n clientRef.current\n ) {\n return;\n }\n\n const { AccountType } = await import('@miden-sdk/miden-sdk');\n\n const { client: midenParaClient, accountId: aId } =\n await createParaMidenClient(\n para,\n evmWallets as Wallet[],\n {\n ...opts,\n endpoint: nodeUrl,\n type: AccountType.RegularAccountImmutableCode,\n storageMode,\n },\n showSigningModal,\n customSignConfirmStep\n );\n\n if (cancelled) {\n return;\n }\n\n clientRef.current = midenParaClient;\n setAccountId(aId);\n }\n\n setupClient();\n\n return () => {\n cancelled = true;\n };\n }, [\n isConnected,\n evmWallets,\n para,\n nodeUrl,\n showSigningModal,\n customSignConfirmStep,\n ]);\n\n return {\n client: clientRef.current,\n accountId,\n para,\n evmWallets,\n nodeUrl,\n opts,\n };\n}\n","import {\n useState,\n useEffect,\n useCallback,\n useRef,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\nimport { ParaWeb, Environment, type Wallet } from '@getpara/web-sdk';\nimport {\n ParaProvider,\n useClient,\n useModal,\n useLogout,\n type ParaProviderProps,\n} from '@getpara/react-sdk-lite';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { SignerContext, type SignerContextValue } from '@miden-sdk/react';\nimport { signCb as createSignCb, type CustomSignConfirmStep } from '@miden-sdk/miden-para';\nimport { evmPkToCommitment, getUncompressedPublicKeyFromWallet } from '@miden-sdk/miden-para';\n\n// Re-export Para hooks for convenience\nexport { useModal, useLogout } from '@getpara/react-sdk-lite';\n\nconst defaultQueryClient = new QueryClient();\n\n// PARA SIGNER PROVIDER\n// ================================================================================================\n\n/** Environment string values accepted by ParaSignerProvider */\nexport type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT' | 'PRODUCTION';\n\n/**\n * Convert environment string to Environment enum value.\n * Handles the mapping safely for both ESM and CJS environments.\n */\nfunction getEnvironmentValue(env: ParaEnvironment): Environment {\n // Handle aliases\n const normalizedEnv = env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;\n\n // Try accessing the enum - Environment may be undefined in some test environments\n if (Environment && typeof Environment === 'object') {\n const value = Environment[normalizedEnv as keyof typeof Environment];\n if (value !== undefined) return value;\n }\n\n // Fallback: return the string directly (Para SDK may accept string values)\n return normalizedEnv as unknown as Environment;\n}\n\nexport interface ParaSignerProviderProps {\n children: ReactNode;\n /** Para API key */\n apiKey: string;\n /** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */\n environment: ParaEnvironment;\n /** App name displayed in Para modal */\n appName?: string;\n /** Whether to show the signing modal for transaction confirmation */\n showSigningModal?: boolean;\n /** Custom sign confirmation step callback */\n customSignConfirmStep?: CustomSignConfirmStep;\n /**\n * Optional custom QueryClient instance for React Query.\n * If not provided, a default instance is used internally.\n */\n queryClient?: QueryClient;\n /**\n * Advanced: Additional config to pass to ParaProvider.\n * Use this for customizing OAuth methods, external wallets, etc.\n */\n paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;\n}\n\n/**\n * Para-specific extras exposed via useParaSigner hook.\n */\nexport interface ParaSignerExtras {\n /** Para client instance */\n para: ParaWeb;\n /** Connected wallet (null if not connected) */\n wallet: Wallet | null;\n}\n\nconst ParaSignerExtrasContext = createContext<ParaSignerExtras | null>(null);\n\n/**\n * ParaSignerProvider wraps MidenProvider to enable Para wallet signing.\n * Includes ParaProvider internally, so you don't need to wrap with it separately.\n *\n * @example\n * ```tsx\n * <ParaSignerProvider apiKey=\"your-api-key\" environment=\"BETA\" appName=\"My App\">\n * <MidenProvider config={{ rpcUrl: \"testnet\" }}>\n * <App />\n * </MidenProvider>\n * </ParaSignerProvider>\n * ```\n */\nexport function ParaSignerProvider({\n children,\n apiKey,\n environment,\n appName = 'Miden App',\n showSigningModal = true,\n customSignConfirmStep,\n queryClient,\n paraProviderConfig,\n}: ParaSignerProviderProps) {\n return (\n <QueryClientProvider client={queryClient ?? defaultQueryClient}>\n <ParaProvider\n paraClientConfig={{\n env: getEnvironmentValue(environment),\n apiKey,\n }}\n config={{ appName }}\n {...paraProviderConfig}\n >\n <ParaSignerProviderInner\n showSigningModal={showSigningModal}\n customSignConfirmStep={customSignConfirmStep}\n >\n {children}\n </ParaSignerProviderInner>\n </ParaProvider>\n </QueryClientProvider>\n );\n}\n\n/**\n * Inner component that has access to ParaProvider context (useModal, etc.)\n */\nfunction ParaSignerProviderInner({\n children,\n showSigningModal = true,\n customSignConfirmStep,\n}: Pick<ParaSignerProviderProps, 'children' | 'showSigningModal' | 'customSignConfirmStep'>) {\n // Access Para modal from ParaProvider.\n // Store in refs to avoid re-render loops (these hooks return new objects each render).\n const { openModal } = useModal();\n const { logoutAsync } = useLogout();\n const openModalRef = useRef(openModal);\n const logoutAsyncRef = useRef(logoutAsync);\n useEffect(() => { openModalRef.current = openModal; }, [openModal]);\n useEffect(() => { logoutAsyncRef.current = logoutAsync; }, [logoutAsync]);\n\n // Get the Para client from ParaProvider context (avoids creating a duplicate instance).\n // Store in a ref so downstream effects don't re-fire when the hook returns a new wrapper.\n const para = useClient()!;\n const paraRef = useRef(para);\n useEffect(() => { paraRef.current = para; }, [para]);\n\n // Keep props in refs so buildContext doesn't re-run when parent re-renders with new closures.\n const showSigningModalRef = useRef(showSigningModal);\n const customSignConfirmStepRef = useRef(customSignConfirmStep);\n useEffect(() => { showSigningModalRef.current = showSigningModal; }, [showSigningModal]);\n useEffect(() => { customSignConfirmStepRef.current = customSignConfirmStep; }, [customSignConfirmStep]);\n\n const [wallet, setWallet] = useState<Wallet | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n\n // Check connection status on mount and periodically\n useEffect(() => {\n let cancelled = false;\n\n async function checkConnection() {\n try {\n const isLoggedIn = await paraRef.current.isFullyLoggedIn();\n if (!isLoggedIn || cancelled) {\n setIsConnected(false);\n setWallet(null);\n return;\n }\n\n const wallets = Object.values(await paraRef.current.getWallets());\n const evmWallets = wallets.filter((w) => w.type === 'EVM');\n\n if (evmWallets.length > 0 && !cancelled) {\n setWallet((prev) => prev?.id === evmWallets[0].id ? prev : evmWallets[0]);\n setIsConnected(true);\n } else if (!cancelled) {\n setIsConnected(false);\n setWallet(null);\n }\n } catch {\n if (!cancelled) {\n setIsConnected(false);\n setWallet(null);\n }\n }\n }\n\n checkConnection();\n const interval = setInterval(checkConnection, 2000);\n return () => {\n cancelled = true;\n clearInterval(interval);\n };\n }, []);\n\n // Connect opens the Para modal\n const connect = useCallback(async () => {\n openModalRef.current();\n }, []);\n\n // Disconnect logs out from Para\n const disconnect = useCallback(async () => {\n await logoutAsyncRef.current();\n await paraRef.current.logout();\n setIsConnected(false);\n setWallet(null);\n }, []);\n\n // Build signer context (includes connect/disconnect for unified useSigner hook).\n // Only depends on isConnected and wallet — everything else is accessed via refs\n // so that MidenProvider doesn't see a new context object on every poll cycle.\n //\n // IMPORTANT: initialise with a disconnected placeholder (isConnected:false) rather\n // than null. When signerContext is null MidenProvider creates a local-keystore\n // client whose auto-sync accesses the WASM module; our buildContext also touches\n // WASM (evmPkToCommitment / AccountStorageMode) → concurrent WASM access → crash.\n // A {isConnected:false} context makes MidenProvider's init effect return early\n // without creating any client, keeping the WASM module free for buildContext.\n const disconnectedCtx = useRef<SignerContextValue>({\n signCb: async () => { throw new Error('Para wallet not connected'); },\n accountConfig: null as any,\n storeName: '',\n name: 'Para',\n isConnected: false,\n connect,\n disconnect,\n });\n const [signerContext, setSignerContext] = useState<SignerContextValue>(\n disconnectedCtx.current\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function buildContext() {\n if (!isConnected || !wallet) {\n setSignerContext(disconnectedCtx.current);\n return;\n }\n\n try {\n // Connected - build full context with signing capability\n const p = paraRef.current;\n const publicKey = await getUncompressedPublicKeyFromWallet(p, wallet);\n if (!publicKey) throw new Error('Failed to get public key from wallet');\n const commitment = await evmPkToCommitment(publicKey);\n\n // Serialize the commitment Word to Uint8Array for SignerAccountConfig\n const commitmentBytes = commitment.serialize();\n\n const signCallback = createSignCb(\n p,\n wallet,\n showSigningModalRef.current,\n customSignConfirmStepRef.current\n );\n\n if (!cancelled) {\n const { AccountStorageMode } = await import(\n '@miden-sdk/miden-sdk'\n );\n\n setSignerContext({\n signCb: signCallback,\n accountConfig: {\n publicKeyCommitment: commitmentBytes,\n accountType: 'RegularAccountImmutableCode',\n storageMode: AccountStorageMode.public(),\n },\n storeName: `para_${wallet.id}`,\n name: 'Para',\n isConnected: true,\n connect,\n disconnect,\n });\n }\n } catch (error) {\n console.error('Failed to build Para signer context:', error);\n if (!cancelled) {\n setSignerContext(disconnectedCtx.current);\n }\n }\n }\n\n buildContext();\n return () => {\n cancelled = true;\n };\n }, [isConnected, wallet, connect, disconnect]);\n\n return (\n <ParaSignerExtrasContext.Provider value={{ para, wallet }}>\n <SignerContext.Provider value={signerContext}>\n {children}\n </SignerContext.Provider>\n </ParaSignerExtrasContext.Provider>\n );\n}\n\n/**\n * Hook for Para-specific extras beyond the unified useSigner interface.\n * Use this to access the Para client or wallet details directly.\n *\n * @example\n * ```tsx\n * const { para, wallet, isConnected } = useParaSigner();\n * ```\n */\nexport function useParaSigner(): ParaSignerExtras & { isConnected: boolean } {\n const extras = useContext(ParaSignerExtrasContext);\n const signer = useContext(SignerContext);\n if (!extras) {\n throw new Error('useParaSigner must be used within ParaSignerProvider');\n }\n return { ...extras, isConnected: signer?.isConnected ?? false };\n}\n"],"mappings":"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","names":["import_react","import_react_sdk_lite","import_miden_para","createSignCb"]}
|
package/dist/index.mjs
CHANGED
|
@@ -25,7 +25,7 @@ function useParaMiden(nodeUrl, storageMode = "public", opts = {}, showSigningMod
|
|
|
25
25
|
if (!isConnected || !para || !((_a = embedded.wallets) == null ? void 0 : _a.length) || clientRef.current) {
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
const { AccountType } = await import("@
|
|
28
|
+
const { AccountType } = await import("@miden-sdk/miden-sdk");
|
|
29
29
|
const { client: midenParaClient, accountId: aId } = await createParaMidenClient(
|
|
30
30
|
para,
|
|
31
31
|
evmWallets,
|
|
@@ -65,7 +65,218 @@ function useParaMiden(nodeUrl, storageMode = "public", opts = {}, showSigningMod
|
|
|
65
65
|
opts
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
|
+
|
|
69
|
+
// src/ParaSignerProvider.tsx
|
|
70
|
+
import {
|
|
71
|
+
useState as useState2,
|
|
72
|
+
useEffect as useEffect2,
|
|
73
|
+
useCallback,
|
|
74
|
+
useRef as useRef2,
|
|
75
|
+
createContext,
|
|
76
|
+
useContext
|
|
77
|
+
} from "react";
|
|
78
|
+
import { Environment } from "@getpara/web-sdk";
|
|
79
|
+
import {
|
|
80
|
+
ParaProvider,
|
|
81
|
+
useClient as useClient2,
|
|
82
|
+
useModal,
|
|
83
|
+
useLogout
|
|
84
|
+
} from "@getpara/react-sdk-lite";
|
|
85
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
86
|
+
import { SignerContext } from "@miden-sdk/react";
|
|
87
|
+
import { signCb as createSignCb } from "@miden-sdk/miden-para";
|
|
88
|
+
import { evmPkToCommitment, getUncompressedPublicKeyFromWallet } from "@miden-sdk/miden-para";
|
|
89
|
+
import { useModal as useModal2, useLogout as useLogout2 } from "@getpara/react-sdk-lite";
|
|
90
|
+
import { jsx } from "react/jsx-runtime";
|
|
91
|
+
var defaultQueryClient = new QueryClient();
|
|
92
|
+
function getEnvironmentValue(env) {
|
|
93
|
+
const normalizedEnv = env === "DEVELOPMENT" ? "BETA" : env === "PRODUCTION" ? "PROD" : env;
|
|
94
|
+
if (Environment && typeof Environment === "object") {
|
|
95
|
+
const value = Environment[normalizedEnv];
|
|
96
|
+
if (value !== void 0) return value;
|
|
97
|
+
}
|
|
98
|
+
return normalizedEnv;
|
|
99
|
+
}
|
|
100
|
+
var ParaSignerExtrasContext = createContext(null);
|
|
101
|
+
function ParaSignerProvider({
|
|
102
|
+
children,
|
|
103
|
+
apiKey,
|
|
104
|
+
environment,
|
|
105
|
+
appName = "Miden App",
|
|
106
|
+
showSigningModal = true,
|
|
107
|
+
customSignConfirmStep,
|
|
108
|
+
queryClient,
|
|
109
|
+
paraProviderConfig
|
|
110
|
+
}) {
|
|
111
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient != null ? queryClient : defaultQueryClient, children: /* @__PURE__ */ jsx(
|
|
112
|
+
ParaProvider,
|
|
113
|
+
{
|
|
114
|
+
paraClientConfig: {
|
|
115
|
+
env: getEnvironmentValue(environment),
|
|
116
|
+
apiKey
|
|
117
|
+
},
|
|
118
|
+
config: { appName },
|
|
119
|
+
...paraProviderConfig,
|
|
120
|
+
children: /* @__PURE__ */ jsx(
|
|
121
|
+
ParaSignerProviderInner,
|
|
122
|
+
{
|
|
123
|
+
showSigningModal,
|
|
124
|
+
customSignConfirmStep,
|
|
125
|
+
children
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
) });
|
|
130
|
+
}
|
|
131
|
+
function ParaSignerProviderInner({
|
|
132
|
+
children,
|
|
133
|
+
showSigningModal = true,
|
|
134
|
+
customSignConfirmStep
|
|
135
|
+
}) {
|
|
136
|
+
const { openModal } = useModal();
|
|
137
|
+
const { logoutAsync } = useLogout();
|
|
138
|
+
const openModalRef = useRef2(openModal);
|
|
139
|
+
const logoutAsyncRef = useRef2(logoutAsync);
|
|
140
|
+
useEffect2(() => {
|
|
141
|
+
openModalRef.current = openModal;
|
|
142
|
+
}, [openModal]);
|
|
143
|
+
useEffect2(() => {
|
|
144
|
+
logoutAsyncRef.current = logoutAsync;
|
|
145
|
+
}, [logoutAsync]);
|
|
146
|
+
const para = useClient2();
|
|
147
|
+
const paraRef = useRef2(para);
|
|
148
|
+
useEffect2(() => {
|
|
149
|
+
paraRef.current = para;
|
|
150
|
+
}, [para]);
|
|
151
|
+
const showSigningModalRef = useRef2(showSigningModal);
|
|
152
|
+
const customSignConfirmStepRef = useRef2(customSignConfirmStep);
|
|
153
|
+
useEffect2(() => {
|
|
154
|
+
showSigningModalRef.current = showSigningModal;
|
|
155
|
+
}, [showSigningModal]);
|
|
156
|
+
useEffect2(() => {
|
|
157
|
+
customSignConfirmStepRef.current = customSignConfirmStep;
|
|
158
|
+
}, [customSignConfirmStep]);
|
|
159
|
+
const [wallet, setWallet] = useState2(null);
|
|
160
|
+
const [isConnected, setIsConnected] = useState2(false);
|
|
161
|
+
useEffect2(() => {
|
|
162
|
+
let cancelled = false;
|
|
163
|
+
async function checkConnection() {
|
|
164
|
+
try {
|
|
165
|
+
const isLoggedIn = await paraRef.current.isFullyLoggedIn();
|
|
166
|
+
if (!isLoggedIn || cancelled) {
|
|
167
|
+
setIsConnected(false);
|
|
168
|
+
setWallet(null);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const wallets = Object.values(await paraRef.current.getWallets());
|
|
172
|
+
const evmWallets = wallets.filter((w) => w.type === "EVM");
|
|
173
|
+
if (evmWallets.length > 0 && !cancelled) {
|
|
174
|
+
setWallet((prev) => (prev == null ? void 0 : prev.id) === evmWallets[0].id ? prev : evmWallets[0]);
|
|
175
|
+
setIsConnected(true);
|
|
176
|
+
} else if (!cancelled) {
|
|
177
|
+
setIsConnected(false);
|
|
178
|
+
setWallet(null);
|
|
179
|
+
}
|
|
180
|
+
} catch {
|
|
181
|
+
if (!cancelled) {
|
|
182
|
+
setIsConnected(false);
|
|
183
|
+
setWallet(null);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
checkConnection();
|
|
188
|
+
const interval = setInterval(checkConnection, 2e3);
|
|
189
|
+
return () => {
|
|
190
|
+
cancelled = true;
|
|
191
|
+
clearInterval(interval);
|
|
192
|
+
};
|
|
193
|
+
}, []);
|
|
194
|
+
const connect = useCallback(async () => {
|
|
195
|
+
openModalRef.current();
|
|
196
|
+
}, []);
|
|
197
|
+
const disconnect = useCallback(async () => {
|
|
198
|
+
await logoutAsyncRef.current();
|
|
199
|
+
await paraRef.current.logout();
|
|
200
|
+
setIsConnected(false);
|
|
201
|
+
setWallet(null);
|
|
202
|
+
}, []);
|
|
203
|
+
const disconnectedCtx = useRef2({
|
|
204
|
+
signCb: async () => {
|
|
205
|
+
throw new Error("Para wallet not connected");
|
|
206
|
+
},
|
|
207
|
+
accountConfig: null,
|
|
208
|
+
storeName: "",
|
|
209
|
+
name: "Para",
|
|
210
|
+
isConnected: false,
|
|
211
|
+
connect,
|
|
212
|
+
disconnect
|
|
213
|
+
});
|
|
214
|
+
const [signerContext, setSignerContext] = useState2(
|
|
215
|
+
disconnectedCtx.current
|
|
216
|
+
);
|
|
217
|
+
useEffect2(() => {
|
|
218
|
+
let cancelled = false;
|
|
219
|
+
async function buildContext() {
|
|
220
|
+
if (!isConnected || !wallet) {
|
|
221
|
+
setSignerContext(disconnectedCtx.current);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const p = paraRef.current;
|
|
226
|
+
const publicKey = await getUncompressedPublicKeyFromWallet(p, wallet);
|
|
227
|
+
if (!publicKey) throw new Error("Failed to get public key from wallet");
|
|
228
|
+
const commitment = await evmPkToCommitment(publicKey);
|
|
229
|
+
const commitmentBytes = commitment.serialize();
|
|
230
|
+
const signCallback = createSignCb(
|
|
231
|
+
p,
|
|
232
|
+
wallet,
|
|
233
|
+
showSigningModalRef.current,
|
|
234
|
+
customSignConfirmStepRef.current
|
|
235
|
+
);
|
|
236
|
+
if (!cancelled) {
|
|
237
|
+
const { AccountStorageMode } = await import("@miden-sdk/miden-sdk");
|
|
238
|
+
setSignerContext({
|
|
239
|
+
signCb: signCallback,
|
|
240
|
+
accountConfig: {
|
|
241
|
+
publicKeyCommitment: commitmentBytes,
|
|
242
|
+
accountType: "RegularAccountImmutableCode",
|
|
243
|
+
storageMode: AccountStorageMode.public()
|
|
244
|
+
},
|
|
245
|
+
storeName: `para_${wallet.id}`,
|
|
246
|
+
name: "Para",
|
|
247
|
+
isConnected: true,
|
|
248
|
+
connect,
|
|
249
|
+
disconnect
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.error("Failed to build Para signer context:", error);
|
|
254
|
+
if (!cancelled) {
|
|
255
|
+
setSignerContext(disconnectedCtx.current);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
buildContext();
|
|
260
|
+
return () => {
|
|
261
|
+
cancelled = true;
|
|
262
|
+
};
|
|
263
|
+
}, [isConnected, wallet, connect, disconnect]);
|
|
264
|
+
return /* @__PURE__ */ jsx(ParaSignerExtrasContext.Provider, { value: { para, wallet }, children: /* @__PURE__ */ jsx(SignerContext.Provider, { value: signerContext, children }) });
|
|
265
|
+
}
|
|
266
|
+
function useParaSigner() {
|
|
267
|
+
var _a;
|
|
268
|
+
const extras = useContext(ParaSignerExtrasContext);
|
|
269
|
+
const signer = useContext(SignerContext);
|
|
270
|
+
if (!extras) {
|
|
271
|
+
throw new Error("useParaSigner must be used within ParaSignerProvider");
|
|
272
|
+
}
|
|
273
|
+
return { ...extras, isConnected: (_a = signer == null ? void 0 : signer.isConnected) != null ? _a : false };
|
|
274
|
+
}
|
|
68
275
|
export {
|
|
69
|
-
|
|
276
|
+
ParaSignerProvider,
|
|
277
|
+
useLogout2 as useLogout,
|
|
278
|
+
useModal2 as useModal,
|
|
279
|
+
useParaMiden,
|
|
280
|
+
useParaSigner
|
|
70
281
|
};
|
|
71
282
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useParaMiden.ts"],"sourcesContent":["'use client';\n\nimport { useClient, useAccount, type Wallet } from '@getpara/react-sdk-lite';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createParaMidenClient,\n type Opts,\n type MidenAccountStorageMode,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\n\n/**\n * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.\n * Spawns the client once a Para session with at least one EVM wallet is active.\n *\n * Returns:\n * - client: WebClient instance backed by the active Para session (or null while loading)\n * - accountId: Miden account id derived for the selected EVM wallet\n * - para: Para client instance from context\n * - evmWallets: filtered list of Para wallets with type === 'EVM'\n * - nodeUrl: Miden node endpoint used for the client\n * - opts: forwarded options used when creating the client\n * - showSigningModal: toggles the built-in signing modal\n * - customSignConfirmStep: optional callback for custom transaction confirmation flows\n */\nexport function useParaMiden(\n nodeUrl: string,\n storageMode: MidenAccountStorageMode = 'public',\n opts: Omit<Opts, 'endpoint' | 'type' | 'storageMode'> = {},\n showSigningModal: boolean = true,\n customSignConfirmStep?: CustomSignConfirmStep\n) {\n const para = useClient();\n const { isConnected, embedded } = useAccount();\n const clientRef = useRef<import('@demox-labs/miden-sdk').WebClient | null>(\n null\n );\n const [accountId, setAccountId] = useState<string>('');\n\n const evmWallets = useMemo(\n () => embedded.wallets?.filter((wallet) => wallet.type === 'EVM'),\n [embedded.wallets]\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function setupClient() {\n if (\n !isConnected ||\n !para ||\n !embedded.wallets?.length ||\n clientRef.current\n ) {\n return;\n }\n\n const { AccountType } = await import('@demox-labs/miden-sdk');\n\n const { client: midenParaClient, accountId: aId } =\n await createParaMidenClient(\n para,\n evmWallets as Wallet[],\n {\n ...opts,\n endpoint: nodeUrl,\n type: AccountType.RegularAccountImmutableCode,\n storageMode,\n },\n showSigningModal,\n customSignConfirmStep\n );\n\n if (cancelled) {\n return;\n }\n\n clientRef.current = midenParaClient;\n setAccountId(aId);\n }\n\n setupClient();\n\n return () => {\n cancelled = true;\n };\n }, [\n isConnected,\n evmWallets,\n para,\n nodeUrl,\n showSigningModal,\n customSignConfirmStep,\n ]);\n\n return {\n client: clientRef.current,\n accountId,\n para,\n evmWallets,\n nodeUrl,\n opts,\n };\n}\n"],"mappings":";AAEA,SAAS,WAAW,kBAA+B;AACnD,SAAS,WAAW,SAAS,QAAQ,gBAAgB;AACrD;AAAA,EACE;AAAA,OAIK;AAgBA,SAAS,aACd,SACA,cAAuC,UACvC,OAAwD,CAAC,GACzD,mBAA4B,MAC5B,uBACA;AACA,QAAM,OAAO,UAAU;AACvB,QAAM,EAAE,aAAa,SAAS,IAAI,WAAW;AAC7C,QAAM,YAAY;AAAA,IAChB;AAAA,EACF;AACA,QAAM,CAAC,WAAW,YAAY,IAAI,SAAiB,EAAE;AAErD,QAAM,aAAa;AAAA,IACjB,MAAG;AAxCP;AAwCU,4BAAS,YAAT,mBAAkB,OAAO,CAAC,WAAW,OAAO,SAAS;AAAA;AAAA,IAC3D,CAAC,SAAS,OAAO;AAAA,EACnB;AAEA,YAAU,MAAM;AACd,QAAI,YAAY;AAEhB,mBAAe,cAAc;AA/CjC;AAgDM,UACE,CAAC,eACD,CAAC,QACD,GAAC,cAAS,YAAT,mBAAkB,WACnB,UAAU,SACV;AACA;AAAA,MACF;AAEA,YAAM,EAAE,YAAY,IAAI,MAAM,OAAO,uBAAuB;AAE5D,YAAM,EAAE,QAAQ,iBAAiB,WAAW,IAAI,IAC9C,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,UACE,GAAG;AAAA,UACH,UAAU;AAAA,UACV,MAAM,YAAY;AAAA,UAClB;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEF,UAAI,WAAW;AACb;AAAA,MACF;AAEA,gBAAU,UAAU;AACpB,mBAAa,GAAG;AAAA,IAClB;AAEA,gBAAY;AAEZ,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,QAAQ,UAAU;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/useParaMiden.ts","../src/ParaSignerProvider.tsx"],"sourcesContent":["'use client';\n\nimport { useClient, useAccount, type Wallet } from '@getpara/react-sdk-lite';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createParaMidenClient,\n type Opts,\n type MidenAccountStorageMode,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\n\n/**\n * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.\n * Spawns the client once a Para session with at least one EVM wallet is active.\n *\n * Returns:\n * - client: WebClient instance backed by the active Para session (or null while loading)\n * - accountId: Miden account id derived for the selected EVM wallet\n * - para: Para client instance from context\n * - evmWallets: filtered list of Para wallets with type === 'EVM'\n * - nodeUrl: Miden node endpoint used for the client\n * - opts: forwarded options used when creating the client\n * - showSigningModal: toggles the built-in signing modal\n * - customSignConfirmStep: optional callback for custom transaction confirmation flows\n */\nexport function useParaMiden(\n nodeUrl: string,\n storageMode: MidenAccountStorageMode = 'public',\n opts: Omit<Opts, 'endpoint' | 'type' | 'storageMode'> = {},\n showSigningModal: boolean = true,\n customSignConfirmStep?: CustomSignConfirmStep\n) {\n const para = useClient();\n const { isConnected, embedded } = useAccount();\n const clientRef = useRef<import('@miden-sdk/miden-sdk').WebClient | null>(\n null\n );\n const [accountId, setAccountId] = useState<string>('');\n\n const evmWallets = useMemo(\n () => embedded.wallets?.filter((wallet) => wallet.type === 'EVM'),\n [embedded.wallets]\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function setupClient() {\n if (\n !isConnected ||\n !para ||\n !embedded.wallets?.length ||\n clientRef.current\n ) {\n return;\n }\n\n const { AccountType } = await import('@miden-sdk/miden-sdk');\n\n const { client: midenParaClient, accountId: aId } =\n await createParaMidenClient(\n para,\n evmWallets as Wallet[],\n {\n ...opts,\n endpoint: nodeUrl,\n type: AccountType.RegularAccountImmutableCode,\n storageMode,\n },\n showSigningModal,\n customSignConfirmStep\n );\n\n if (cancelled) {\n return;\n }\n\n clientRef.current = midenParaClient;\n setAccountId(aId);\n }\n\n setupClient();\n\n return () => {\n cancelled = true;\n };\n }, [\n isConnected,\n evmWallets,\n para,\n nodeUrl,\n showSigningModal,\n customSignConfirmStep,\n ]);\n\n return {\n client: clientRef.current,\n accountId,\n para,\n evmWallets,\n nodeUrl,\n opts,\n };\n}\n","import {\n useState,\n useEffect,\n useCallback,\n useRef,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\nimport { ParaWeb, Environment, type Wallet } from '@getpara/web-sdk';\nimport {\n ParaProvider,\n useClient,\n useModal,\n useLogout,\n type ParaProviderProps,\n} from '@getpara/react-sdk-lite';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { SignerContext, type SignerContextValue } from '@miden-sdk/react';\nimport { signCb as createSignCb, type CustomSignConfirmStep } from '@miden-sdk/miden-para';\nimport { evmPkToCommitment, getUncompressedPublicKeyFromWallet } from '@miden-sdk/miden-para';\n\n// Re-export Para hooks for convenience\nexport { useModal, useLogout } from '@getpara/react-sdk-lite';\n\nconst defaultQueryClient = new QueryClient();\n\n// PARA SIGNER PROVIDER\n// ================================================================================================\n\n/** Environment string values accepted by ParaSignerProvider */\nexport type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT' | 'PRODUCTION';\n\n/**\n * Convert environment string to Environment enum value.\n * Handles the mapping safely for both ESM and CJS environments.\n */\nfunction getEnvironmentValue(env: ParaEnvironment): Environment {\n // Handle aliases\n const normalizedEnv = env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;\n\n // Try accessing the enum - Environment may be undefined in some test environments\n if (Environment && typeof Environment === 'object') {\n const value = Environment[normalizedEnv as keyof typeof Environment];\n if (value !== undefined) return value;\n }\n\n // Fallback: return the string directly (Para SDK may accept string values)\n return normalizedEnv as unknown as Environment;\n}\n\nexport interface ParaSignerProviderProps {\n children: ReactNode;\n /** Para API key */\n apiKey: string;\n /** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */\n environment: ParaEnvironment;\n /** App name displayed in Para modal */\n appName?: string;\n /** Whether to show the signing modal for transaction confirmation */\n showSigningModal?: boolean;\n /** Custom sign confirmation step callback */\n customSignConfirmStep?: CustomSignConfirmStep;\n /**\n * Optional custom QueryClient instance for React Query.\n * If not provided, a default instance is used internally.\n */\n queryClient?: QueryClient;\n /**\n * Advanced: Additional config to pass to ParaProvider.\n * Use this for customizing OAuth methods, external wallets, etc.\n */\n paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;\n}\n\n/**\n * Para-specific extras exposed via useParaSigner hook.\n */\nexport interface ParaSignerExtras {\n /** Para client instance */\n para: ParaWeb;\n /** Connected wallet (null if not connected) */\n wallet: Wallet | null;\n}\n\nconst ParaSignerExtrasContext = createContext<ParaSignerExtras | null>(null);\n\n/**\n * ParaSignerProvider wraps MidenProvider to enable Para wallet signing.\n * Includes ParaProvider internally, so you don't need to wrap with it separately.\n *\n * @example\n * ```tsx\n * <ParaSignerProvider apiKey=\"your-api-key\" environment=\"BETA\" appName=\"My App\">\n * <MidenProvider config={{ rpcUrl: \"testnet\" }}>\n * <App />\n * </MidenProvider>\n * </ParaSignerProvider>\n * ```\n */\nexport function ParaSignerProvider({\n children,\n apiKey,\n environment,\n appName = 'Miden App',\n showSigningModal = true,\n customSignConfirmStep,\n queryClient,\n paraProviderConfig,\n}: ParaSignerProviderProps) {\n return (\n <QueryClientProvider client={queryClient ?? defaultQueryClient}>\n <ParaProvider\n paraClientConfig={{\n env: getEnvironmentValue(environment),\n apiKey,\n }}\n config={{ appName }}\n {...paraProviderConfig}\n >\n <ParaSignerProviderInner\n showSigningModal={showSigningModal}\n customSignConfirmStep={customSignConfirmStep}\n >\n {children}\n </ParaSignerProviderInner>\n </ParaProvider>\n </QueryClientProvider>\n );\n}\n\n/**\n * Inner component that has access to ParaProvider context (useModal, etc.)\n */\nfunction ParaSignerProviderInner({\n children,\n showSigningModal = true,\n customSignConfirmStep,\n}: Pick<ParaSignerProviderProps, 'children' | 'showSigningModal' | 'customSignConfirmStep'>) {\n // Access Para modal from ParaProvider.\n // Store in refs to avoid re-render loops (these hooks return new objects each render).\n const { openModal } = useModal();\n const { logoutAsync } = useLogout();\n const openModalRef = useRef(openModal);\n const logoutAsyncRef = useRef(logoutAsync);\n useEffect(() => { openModalRef.current = openModal; }, [openModal]);\n useEffect(() => { logoutAsyncRef.current = logoutAsync; }, [logoutAsync]);\n\n // Get the Para client from ParaProvider context (avoids creating a duplicate instance).\n // Store in a ref so downstream effects don't re-fire when the hook returns a new wrapper.\n const para = useClient()!;\n const paraRef = useRef(para);\n useEffect(() => { paraRef.current = para; }, [para]);\n\n // Keep props in refs so buildContext doesn't re-run when parent re-renders with new closures.\n const showSigningModalRef = useRef(showSigningModal);\n const customSignConfirmStepRef = useRef(customSignConfirmStep);\n useEffect(() => { showSigningModalRef.current = showSigningModal; }, [showSigningModal]);\n useEffect(() => { customSignConfirmStepRef.current = customSignConfirmStep; }, [customSignConfirmStep]);\n\n const [wallet, setWallet] = useState<Wallet | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n\n // Check connection status on mount and periodically\n useEffect(() => {\n let cancelled = false;\n\n async function checkConnection() {\n try {\n const isLoggedIn = await paraRef.current.isFullyLoggedIn();\n if (!isLoggedIn || cancelled) {\n setIsConnected(false);\n setWallet(null);\n return;\n }\n\n const wallets = Object.values(await paraRef.current.getWallets());\n const evmWallets = wallets.filter((w) => w.type === 'EVM');\n\n if (evmWallets.length > 0 && !cancelled) {\n setWallet((prev) => prev?.id === evmWallets[0].id ? prev : evmWallets[0]);\n setIsConnected(true);\n } else if (!cancelled) {\n setIsConnected(false);\n setWallet(null);\n }\n } catch {\n if (!cancelled) {\n setIsConnected(false);\n setWallet(null);\n }\n }\n }\n\n checkConnection();\n const interval = setInterval(checkConnection, 2000);\n return () => {\n cancelled = true;\n clearInterval(interval);\n };\n }, []);\n\n // Connect opens the Para modal\n const connect = useCallback(async () => {\n openModalRef.current();\n }, []);\n\n // Disconnect logs out from Para\n const disconnect = useCallback(async () => {\n await logoutAsyncRef.current();\n await paraRef.current.logout();\n setIsConnected(false);\n setWallet(null);\n }, []);\n\n // Build signer context (includes connect/disconnect for unified useSigner hook).\n // Only depends on isConnected and wallet — everything else is accessed via refs\n // so that MidenProvider doesn't see a new context object on every poll cycle.\n //\n // IMPORTANT: initialise with a disconnected placeholder (isConnected:false) rather\n // than null. When signerContext is null MidenProvider creates a local-keystore\n // client whose auto-sync accesses the WASM module; our buildContext also touches\n // WASM (evmPkToCommitment / AccountStorageMode) → concurrent WASM access → crash.\n // A {isConnected:false} context makes MidenProvider's init effect return early\n // without creating any client, keeping the WASM module free for buildContext.\n const disconnectedCtx = useRef<SignerContextValue>({\n signCb: async () => { throw new Error('Para wallet not connected'); },\n accountConfig: null as any,\n storeName: '',\n name: 'Para',\n isConnected: false,\n connect,\n disconnect,\n });\n const [signerContext, setSignerContext] = useState<SignerContextValue>(\n disconnectedCtx.current\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function buildContext() {\n if (!isConnected || !wallet) {\n setSignerContext(disconnectedCtx.current);\n return;\n }\n\n try {\n // Connected - build full context with signing capability\n const p = paraRef.current;\n const publicKey = await getUncompressedPublicKeyFromWallet(p, wallet);\n if (!publicKey) throw new Error('Failed to get public key from wallet');\n const commitment = await evmPkToCommitment(publicKey);\n\n // Serialize the commitment Word to Uint8Array for SignerAccountConfig\n const commitmentBytes = commitment.serialize();\n\n const signCallback = createSignCb(\n p,\n wallet,\n showSigningModalRef.current,\n customSignConfirmStepRef.current\n );\n\n if (!cancelled) {\n const { AccountStorageMode } = await import(\n '@miden-sdk/miden-sdk'\n );\n\n setSignerContext({\n signCb: signCallback,\n accountConfig: {\n publicKeyCommitment: commitmentBytes,\n accountType: 'RegularAccountImmutableCode',\n storageMode: AccountStorageMode.public(),\n },\n storeName: `para_${wallet.id}`,\n name: 'Para',\n isConnected: true,\n connect,\n disconnect,\n });\n }\n } catch (error) {\n console.error('Failed to build Para signer context:', error);\n if (!cancelled) {\n setSignerContext(disconnectedCtx.current);\n }\n }\n }\n\n buildContext();\n return () => {\n cancelled = true;\n };\n }, [isConnected, wallet, connect, disconnect]);\n\n return (\n <ParaSignerExtrasContext.Provider value={{ para, wallet }}>\n <SignerContext.Provider value={signerContext}>\n {children}\n </SignerContext.Provider>\n </ParaSignerExtrasContext.Provider>\n );\n}\n\n/**\n * Hook for Para-specific extras beyond the unified useSigner interface.\n * Use this to access the Para client or wallet details directly.\n *\n * @example\n * ```tsx\n * const { para, wallet, isConnected } = useParaSigner();\n * ```\n */\nexport function useParaSigner(): ParaSignerExtras & { isConnected: boolean } {\n const extras = useContext(ParaSignerExtrasContext);\n const signer = useContext(SignerContext);\n if (!extras) {\n throw new Error('useParaSigner must be used within ParaSignerProvider');\n }\n return { ...extras, isConnected: signer?.isConnected ?? false };\n}\n"],"mappings":"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","names":["useState","useEffect","useRef","useClient","useModal","useLogout"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miden-sdk/use-miden-para-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "React hook that wires Para accounts into a Miden client",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Miden Labs",
|
|
@@ -36,17 +36,23 @@
|
|
|
36
36
|
"publish": "npm run build && npm publish --access public"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@
|
|
39
|
+
"@miden-sdk/miden-sdk": "^0.13.0",
|
|
40
40
|
"@getpara/react-sdk-lite": "^2.2.0",
|
|
41
|
-
"@
|
|
41
|
+
"@getpara/web-sdk": "2.0.0-alpha.73",
|
|
42
|
+
"@miden-sdk/miden-para": "^0.13.0",
|
|
43
|
+
"@miden-sdk/react": "^0.13.1",
|
|
44
|
+
"@tanstack/react-query": "^5.0.0",
|
|
42
45
|
"react": "^18.0.0 || ^19.0.0"
|
|
43
46
|
},
|
|
44
47
|
"devDependencies": {
|
|
45
|
-
"@
|
|
48
|
+
"@miden-sdk/miden-sdk": "^0.13.0",
|
|
49
|
+
"@getpara/react-sdk-lite": "^2.3.0",
|
|
50
|
+
"@getpara/web-sdk": "2.0.0-alpha.73",
|
|
51
|
+
"@miden-sdk/react": "^0.13.1",
|
|
52
|
+
"@tanstack/react-query": "^5.90.12",
|
|
46
53
|
"@types/react": "^19.2.5",
|
|
47
54
|
"tsup": "^8.3.0",
|
|
48
|
-
"typescript": "^5.9.3"
|
|
49
|
-
"@getpara/react-sdk-lite": "^2.3.0"
|
|
55
|
+
"typescript": "^5.9.3"
|
|
50
56
|
},
|
|
51
57
|
"engines": {
|
|
52
58
|
"node": ">=18"
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useState,
|
|
3
|
+
useEffect,
|
|
4
|
+
useCallback,
|
|
5
|
+
useRef,
|
|
6
|
+
createContext,
|
|
7
|
+
useContext,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import { ParaWeb, Environment, type Wallet } from '@getpara/web-sdk';
|
|
11
|
+
import {
|
|
12
|
+
ParaProvider,
|
|
13
|
+
useClient,
|
|
14
|
+
useModal,
|
|
15
|
+
useLogout,
|
|
16
|
+
type ParaProviderProps,
|
|
17
|
+
} from '@getpara/react-sdk-lite';
|
|
18
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
19
|
+
import { SignerContext, type SignerContextValue } from '@miden-sdk/react';
|
|
20
|
+
import { signCb as createSignCb, type CustomSignConfirmStep } from '@miden-sdk/miden-para';
|
|
21
|
+
import { evmPkToCommitment, getUncompressedPublicKeyFromWallet } from '@miden-sdk/miden-para';
|
|
22
|
+
|
|
23
|
+
// Re-export Para hooks for convenience
|
|
24
|
+
export { useModal, useLogout } from '@getpara/react-sdk-lite';
|
|
25
|
+
|
|
26
|
+
const defaultQueryClient = new QueryClient();
|
|
27
|
+
|
|
28
|
+
// PARA SIGNER PROVIDER
|
|
29
|
+
// ================================================================================================
|
|
30
|
+
|
|
31
|
+
/** Environment string values accepted by ParaSignerProvider */
|
|
32
|
+
export type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT' | 'PRODUCTION';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Convert environment string to Environment enum value.
|
|
36
|
+
* Handles the mapping safely for both ESM and CJS environments.
|
|
37
|
+
*/
|
|
38
|
+
function getEnvironmentValue(env: ParaEnvironment): Environment {
|
|
39
|
+
// Handle aliases
|
|
40
|
+
const normalizedEnv = env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;
|
|
41
|
+
|
|
42
|
+
// Try accessing the enum - Environment may be undefined in some test environments
|
|
43
|
+
if (Environment && typeof Environment === 'object') {
|
|
44
|
+
const value = Environment[normalizedEnv as keyof typeof Environment];
|
|
45
|
+
if (value !== undefined) return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Fallback: return the string directly (Para SDK may accept string values)
|
|
49
|
+
return normalizedEnv as unknown as Environment;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ParaSignerProviderProps {
|
|
53
|
+
children: ReactNode;
|
|
54
|
+
/** Para API key */
|
|
55
|
+
apiKey: string;
|
|
56
|
+
/** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */
|
|
57
|
+
environment: ParaEnvironment;
|
|
58
|
+
/** App name displayed in Para modal */
|
|
59
|
+
appName?: string;
|
|
60
|
+
/** Whether to show the signing modal for transaction confirmation */
|
|
61
|
+
showSigningModal?: boolean;
|
|
62
|
+
/** Custom sign confirmation step callback */
|
|
63
|
+
customSignConfirmStep?: CustomSignConfirmStep;
|
|
64
|
+
/**
|
|
65
|
+
* Optional custom QueryClient instance for React Query.
|
|
66
|
+
* If not provided, a default instance is used internally.
|
|
67
|
+
*/
|
|
68
|
+
queryClient?: QueryClient;
|
|
69
|
+
/**
|
|
70
|
+
* Advanced: Additional config to pass to ParaProvider.
|
|
71
|
+
* Use this for customizing OAuth methods, external wallets, etc.
|
|
72
|
+
*/
|
|
73
|
+
paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Para-specific extras exposed via useParaSigner hook.
|
|
78
|
+
*/
|
|
79
|
+
export interface ParaSignerExtras {
|
|
80
|
+
/** Para client instance */
|
|
81
|
+
para: ParaWeb;
|
|
82
|
+
/** Connected wallet (null if not connected) */
|
|
83
|
+
wallet: Wallet | null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const ParaSignerExtrasContext = createContext<ParaSignerExtras | null>(null);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* ParaSignerProvider wraps MidenProvider to enable Para wallet signing.
|
|
90
|
+
* Includes ParaProvider internally, so you don't need to wrap with it separately.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```tsx
|
|
94
|
+
* <ParaSignerProvider apiKey="your-api-key" environment="BETA" appName="My App">
|
|
95
|
+
* <MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
96
|
+
* <App />
|
|
97
|
+
* </MidenProvider>
|
|
98
|
+
* </ParaSignerProvider>
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export function ParaSignerProvider({
|
|
102
|
+
children,
|
|
103
|
+
apiKey,
|
|
104
|
+
environment,
|
|
105
|
+
appName = 'Miden App',
|
|
106
|
+
showSigningModal = true,
|
|
107
|
+
customSignConfirmStep,
|
|
108
|
+
queryClient,
|
|
109
|
+
paraProviderConfig,
|
|
110
|
+
}: ParaSignerProviderProps) {
|
|
111
|
+
return (
|
|
112
|
+
<QueryClientProvider client={queryClient ?? defaultQueryClient}>
|
|
113
|
+
<ParaProvider
|
|
114
|
+
paraClientConfig={{
|
|
115
|
+
env: getEnvironmentValue(environment),
|
|
116
|
+
apiKey,
|
|
117
|
+
}}
|
|
118
|
+
config={{ appName }}
|
|
119
|
+
{...paraProviderConfig}
|
|
120
|
+
>
|
|
121
|
+
<ParaSignerProviderInner
|
|
122
|
+
showSigningModal={showSigningModal}
|
|
123
|
+
customSignConfirmStep={customSignConfirmStep}
|
|
124
|
+
>
|
|
125
|
+
{children}
|
|
126
|
+
</ParaSignerProviderInner>
|
|
127
|
+
</ParaProvider>
|
|
128
|
+
</QueryClientProvider>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Inner component that has access to ParaProvider context (useModal, etc.)
|
|
134
|
+
*/
|
|
135
|
+
function ParaSignerProviderInner({
|
|
136
|
+
children,
|
|
137
|
+
showSigningModal = true,
|
|
138
|
+
customSignConfirmStep,
|
|
139
|
+
}: Pick<ParaSignerProviderProps, 'children' | 'showSigningModal' | 'customSignConfirmStep'>) {
|
|
140
|
+
// Access Para modal from ParaProvider.
|
|
141
|
+
// Store in refs to avoid re-render loops (these hooks return new objects each render).
|
|
142
|
+
const { openModal } = useModal();
|
|
143
|
+
const { logoutAsync } = useLogout();
|
|
144
|
+
const openModalRef = useRef(openModal);
|
|
145
|
+
const logoutAsyncRef = useRef(logoutAsync);
|
|
146
|
+
useEffect(() => { openModalRef.current = openModal; }, [openModal]);
|
|
147
|
+
useEffect(() => { logoutAsyncRef.current = logoutAsync; }, [logoutAsync]);
|
|
148
|
+
|
|
149
|
+
// Get the Para client from ParaProvider context (avoids creating a duplicate instance).
|
|
150
|
+
// Store in a ref so downstream effects don't re-fire when the hook returns a new wrapper.
|
|
151
|
+
const para = useClient()!;
|
|
152
|
+
const paraRef = useRef(para);
|
|
153
|
+
useEffect(() => { paraRef.current = para; }, [para]);
|
|
154
|
+
|
|
155
|
+
// Keep props in refs so buildContext doesn't re-run when parent re-renders with new closures.
|
|
156
|
+
const showSigningModalRef = useRef(showSigningModal);
|
|
157
|
+
const customSignConfirmStepRef = useRef(customSignConfirmStep);
|
|
158
|
+
useEffect(() => { showSigningModalRef.current = showSigningModal; }, [showSigningModal]);
|
|
159
|
+
useEffect(() => { customSignConfirmStepRef.current = customSignConfirmStep; }, [customSignConfirmStep]);
|
|
160
|
+
|
|
161
|
+
const [wallet, setWallet] = useState<Wallet | null>(null);
|
|
162
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
163
|
+
|
|
164
|
+
// Check connection status on mount and periodically
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
let cancelled = false;
|
|
167
|
+
|
|
168
|
+
async function checkConnection() {
|
|
169
|
+
try {
|
|
170
|
+
const isLoggedIn = await paraRef.current.isFullyLoggedIn();
|
|
171
|
+
if (!isLoggedIn || cancelled) {
|
|
172
|
+
setIsConnected(false);
|
|
173
|
+
setWallet(null);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const wallets = Object.values(await paraRef.current.getWallets());
|
|
178
|
+
const evmWallets = wallets.filter((w) => w.type === 'EVM');
|
|
179
|
+
|
|
180
|
+
if (evmWallets.length > 0 && !cancelled) {
|
|
181
|
+
setWallet((prev) => prev?.id === evmWallets[0].id ? prev : evmWallets[0]);
|
|
182
|
+
setIsConnected(true);
|
|
183
|
+
} else if (!cancelled) {
|
|
184
|
+
setIsConnected(false);
|
|
185
|
+
setWallet(null);
|
|
186
|
+
}
|
|
187
|
+
} catch {
|
|
188
|
+
if (!cancelled) {
|
|
189
|
+
setIsConnected(false);
|
|
190
|
+
setWallet(null);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
checkConnection();
|
|
196
|
+
const interval = setInterval(checkConnection, 2000);
|
|
197
|
+
return () => {
|
|
198
|
+
cancelled = true;
|
|
199
|
+
clearInterval(interval);
|
|
200
|
+
};
|
|
201
|
+
}, []);
|
|
202
|
+
|
|
203
|
+
// Connect opens the Para modal
|
|
204
|
+
const connect = useCallback(async () => {
|
|
205
|
+
openModalRef.current();
|
|
206
|
+
}, []);
|
|
207
|
+
|
|
208
|
+
// Disconnect logs out from Para
|
|
209
|
+
const disconnect = useCallback(async () => {
|
|
210
|
+
await logoutAsyncRef.current();
|
|
211
|
+
await paraRef.current.logout();
|
|
212
|
+
setIsConnected(false);
|
|
213
|
+
setWallet(null);
|
|
214
|
+
}, []);
|
|
215
|
+
|
|
216
|
+
// Build signer context (includes connect/disconnect for unified useSigner hook).
|
|
217
|
+
// Only depends on isConnected and wallet — everything else is accessed via refs
|
|
218
|
+
// so that MidenProvider doesn't see a new context object on every poll cycle.
|
|
219
|
+
//
|
|
220
|
+
// IMPORTANT: initialise with a disconnected placeholder (isConnected:false) rather
|
|
221
|
+
// than null. When signerContext is null MidenProvider creates a local-keystore
|
|
222
|
+
// client whose auto-sync accesses the WASM module; our buildContext also touches
|
|
223
|
+
// WASM (evmPkToCommitment / AccountStorageMode) → concurrent WASM access → crash.
|
|
224
|
+
// A {isConnected:false} context makes MidenProvider's init effect return early
|
|
225
|
+
// without creating any client, keeping the WASM module free for buildContext.
|
|
226
|
+
const disconnectedCtx = useRef<SignerContextValue>({
|
|
227
|
+
signCb: async () => { throw new Error('Para wallet not connected'); },
|
|
228
|
+
accountConfig: null as any,
|
|
229
|
+
storeName: '',
|
|
230
|
+
name: 'Para',
|
|
231
|
+
isConnected: false,
|
|
232
|
+
connect,
|
|
233
|
+
disconnect,
|
|
234
|
+
});
|
|
235
|
+
const [signerContext, setSignerContext] = useState<SignerContextValue>(
|
|
236
|
+
disconnectedCtx.current
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
let cancelled = false;
|
|
241
|
+
|
|
242
|
+
async function buildContext() {
|
|
243
|
+
if (!isConnected || !wallet) {
|
|
244
|
+
setSignerContext(disconnectedCtx.current);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
// Connected - build full context with signing capability
|
|
250
|
+
const p = paraRef.current;
|
|
251
|
+
const publicKey = await getUncompressedPublicKeyFromWallet(p, wallet);
|
|
252
|
+
if (!publicKey) throw new Error('Failed to get public key from wallet');
|
|
253
|
+
const commitment = await evmPkToCommitment(publicKey);
|
|
254
|
+
|
|
255
|
+
// Serialize the commitment Word to Uint8Array for SignerAccountConfig
|
|
256
|
+
const commitmentBytes = commitment.serialize();
|
|
257
|
+
|
|
258
|
+
const signCallback = createSignCb(
|
|
259
|
+
p,
|
|
260
|
+
wallet,
|
|
261
|
+
showSigningModalRef.current,
|
|
262
|
+
customSignConfirmStepRef.current
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
if (!cancelled) {
|
|
266
|
+
const { AccountStorageMode } = await import(
|
|
267
|
+
'@miden-sdk/miden-sdk'
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
setSignerContext({
|
|
271
|
+
signCb: signCallback,
|
|
272
|
+
accountConfig: {
|
|
273
|
+
publicKeyCommitment: commitmentBytes,
|
|
274
|
+
accountType: 'RegularAccountImmutableCode',
|
|
275
|
+
storageMode: AccountStorageMode.public(),
|
|
276
|
+
},
|
|
277
|
+
storeName: `para_${wallet.id}`,
|
|
278
|
+
name: 'Para',
|
|
279
|
+
isConnected: true,
|
|
280
|
+
connect,
|
|
281
|
+
disconnect,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error('Failed to build Para signer context:', error);
|
|
286
|
+
if (!cancelled) {
|
|
287
|
+
setSignerContext(disconnectedCtx.current);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
buildContext();
|
|
293
|
+
return () => {
|
|
294
|
+
cancelled = true;
|
|
295
|
+
};
|
|
296
|
+
}, [isConnected, wallet, connect, disconnect]);
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<ParaSignerExtrasContext.Provider value={{ para, wallet }}>
|
|
300
|
+
<SignerContext.Provider value={signerContext}>
|
|
301
|
+
{children}
|
|
302
|
+
</SignerContext.Provider>
|
|
303
|
+
</ParaSignerExtrasContext.Provider>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Hook for Para-specific extras beyond the unified useSigner interface.
|
|
309
|
+
* Use this to access the Para client or wallet details directly.
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```tsx
|
|
313
|
+
* const { para, wallet, isConnected } = useParaSigner();
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
export function useParaSigner(): ParaSignerExtras & { isConnected: boolean } {
|
|
317
|
+
const extras = useContext(ParaSignerExtrasContext);
|
|
318
|
+
const signer = useContext(SignerContext);
|
|
319
|
+
if (!extras) {
|
|
320
|
+
throw new Error('useParaSigner must be used within ParaSignerProvider');
|
|
321
|
+
}
|
|
322
|
+
return { ...extras, isConnected: signer?.isConnected ?? false };
|
|
323
|
+
}
|
package/src/index.ts
CHANGED
package/src/useParaMiden.ts
CHANGED
|
@@ -32,7 +32,7 @@ export function useParaMiden(
|
|
|
32
32
|
) {
|
|
33
33
|
const para = useClient();
|
|
34
34
|
const { isConnected, embedded } = useAccount();
|
|
35
|
-
const clientRef = useRef<import('@
|
|
35
|
+
const clientRef = useRef<import('@miden-sdk/miden-sdk').WebClient | null>(
|
|
36
36
|
null
|
|
37
37
|
);
|
|
38
38
|
const [accountId, setAccountId] = useState<string>('');
|
|
@@ -55,7 +55,7 @@ export function useParaMiden(
|
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
const { AccountType } = await import('@
|
|
58
|
+
const { AccountType } = await import('@miden-sdk/miden-sdk');
|
|
59
59
|
|
|
60
60
|
const { client: midenParaClient, accountId: aId } =
|
|
61
61
|
await createParaMidenClient(
|