@miden-sdk/react 0.13.2 → 0.14.0-alpha
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/CLAUDE.md +28 -0
- package/README.md +402 -6
- package/dist/index.d.mts +275 -23
- package/dist/index.d.ts +275 -23
- package/dist/index.js +1168 -396
- package/dist/index.mjs +1154 -383
- package/package.json +9 -2
package/CLAUDE.md
CHANGED
|
@@ -332,6 +332,34 @@ import { SignerContext } from "@miden-sdk/react";
|
|
|
332
332
|
</SignerContext.Provider>
|
|
333
333
|
```
|
|
334
334
|
|
|
335
|
+
### Custom Account Components
|
|
336
|
+
|
|
337
|
+
Signer providers can attach custom `AccountComponent` instances to accounts
|
|
338
|
+
via the `customComponents` field on `SignerAccountConfig`. This is useful for
|
|
339
|
+
including application-specific logic compiled from `.masp` packages (e.g. a
|
|
340
|
+
DEX component or custom smart contract) alongside the default auth and basic
|
|
341
|
+
wallet components.
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
import { SignerContext, type SignerAccountConfig } from "@miden-sdk/react";
|
|
345
|
+
import { AccountComponent } from "@miden-sdk/miden-sdk";
|
|
346
|
+
|
|
347
|
+
// Load a compiled .masp component (e.g. from your build pipeline)
|
|
348
|
+
const myDexComponent: AccountComponent = await loadCompiledComponent();
|
|
349
|
+
|
|
350
|
+
const accountConfig: SignerAccountConfig = {
|
|
351
|
+
publicKeyCommitment: userPublicKeyCommitment,
|
|
352
|
+
accountType: "RegularAccountUpdatableCode",
|
|
353
|
+
storageMode: myStorageMode,
|
|
354
|
+
customComponents: [myDexComponent],
|
|
355
|
+
};
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Components are appended to the `AccountBuilder` after the default basic wallet
|
|
359
|
+
component and before `build()` is called, so the account always includes wallet
|
|
360
|
+
functionality plus any extras you provide. The field is optional — omitting it
|
|
361
|
+
or passing an empty array preserves the default behavior.
|
|
362
|
+
|
|
335
363
|
## Account ID Formats
|
|
336
364
|
|
|
337
365
|
Both formats work interchangeably in all hooks:
|
package/README.md
CHANGED
|
@@ -9,6 +9,12 @@ React hooks library for the Miden Web Client. Provides a simple, ergonomic inter
|
|
|
9
9
|
- **Auto-Sync** - Automatic background synchronization with the network
|
|
10
10
|
- **TypeScript First** - Full type safety with comprehensive type exports
|
|
11
11
|
- **Consistent Patterns** - All hooks follow predictable patterns for loading, errors, and state
|
|
12
|
+
- **Note Attachments** - Send and read arbitrary data payloads on notes via `useSend()` and `readNoteAttachment()`
|
|
13
|
+
- **Temporal Note Tracking** - `useNoteStream()` tracks when notes first appear, with built-in filtering, handled-note exclusion, and phase snapshots
|
|
14
|
+
- **Session Wallets** - `useSessionAccount()` manages the create-fund-consume lifecycle for temporary wallets
|
|
15
|
+
- **Concurrency Safety** - Transaction hooks prevent double-sends with built-in concurrency guards
|
|
16
|
+
- **Auto Pre-Sync** - Transaction hooks sync before executing by default (opt out with `skipSync`)
|
|
17
|
+
- **WASM Error Wrapping** - Cryptic WASM errors are intercepted and replaced with actionable messages
|
|
12
18
|
|
|
13
19
|
## Installation
|
|
14
20
|
|
|
@@ -438,6 +444,8 @@ function NotesList() {
|
|
|
438
444
|
const { notes: committedNotes } = useNotes({
|
|
439
445
|
status: 'committed', // 'all' | 'consumed' | 'committed' | 'expected' | 'processing'
|
|
440
446
|
accountId: '0x...', // Filter by account
|
|
447
|
+
sender: '0x...', // Filter by sender (any format, normalized internally)
|
|
448
|
+
excludeIds: ['0xnote1...'], // Exclude specific note IDs
|
|
441
449
|
});
|
|
442
450
|
|
|
443
451
|
return (
|
|
@@ -460,6 +468,61 @@ function NotesList() {
|
|
|
460
468
|
}
|
|
461
469
|
```
|
|
462
470
|
|
|
471
|
+
#### `useNoteStream(options?)`
|
|
472
|
+
|
|
473
|
+
Temporal note tracking with a unified model. Replaces the common pattern of
|
|
474
|
+
`handledNoteIds` refs, deferred baselines, and dual-track note decoding.
|
|
475
|
+
Returns `StreamedNote` objects that merge summary data with the underlying
|
|
476
|
+
record and pre-decode attachments.
|
|
477
|
+
|
|
478
|
+
Features:
|
|
479
|
+
- **Unified `StreamedNote` type** with sender (bech32), amount, assets, attachment, and `firstSeenAt` timestamp
|
|
480
|
+
- **Built-in filtering** by sender, status, `since` timestamp, `excludeIds`, and custom `amountFilter`
|
|
481
|
+
- **`markHandled` / `markAllHandled`** to exclude processed notes without removing them from the store
|
|
482
|
+
- **`snapshot()`** to capture current note IDs and timestamp for passing to the next phase
|
|
483
|
+
|
|
484
|
+
```tsx
|
|
485
|
+
import { useNoteStream } from '@miden-sdk/react';
|
|
486
|
+
|
|
487
|
+
function IncomingNotes({ opponentId }: { opponentId: string }) {
|
|
488
|
+
const { notes, latest, markHandled, snapshot } = useNoteStream({
|
|
489
|
+
sender: opponentId, // Only notes from this sender
|
|
490
|
+
status: 'committed', // 'all' | 'consumed' | 'committed' | 'expected' | 'processing'
|
|
491
|
+
// since: phaseStartTime, // Only notes after this timestamp
|
|
492
|
+
// excludeIds: staleIds, // Exclude specific note IDs
|
|
493
|
+
// amountFilter: (a) => a >= 100n,
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
useEffect(() => {
|
|
497
|
+
if (latest) {
|
|
498
|
+
console.log('New note!', latest.attachment);
|
|
499
|
+
markHandled(latest.id);
|
|
500
|
+
}
|
|
501
|
+
}, [latest, markHandled]);
|
|
502
|
+
|
|
503
|
+
// Capture state for next phase
|
|
504
|
+
const handlePhaseEnd = () => {
|
|
505
|
+
const snap = snapshot(); // { ids: Set<string>, timestamp: number }
|
|
506
|
+
// Pass snap.ids as excludeIds or snap.timestamp as since to next phase
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
return <div>{notes.length} unhandled notes</div>;
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
The `StreamedNote` type provides:
|
|
514
|
+
```typescript
|
|
515
|
+
interface StreamedNote {
|
|
516
|
+
id: string; // Note ID (hex)
|
|
517
|
+
sender: string; // Sender account ID (bech32)
|
|
518
|
+
amount: bigint; // First fungible asset amount (0n if none)
|
|
519
|
+
assets: NoteAsset[]; // All assets on the note
|
|
520
|
+
record: InputNoteRecord; // Underlying record for escape-hatch access
|
|
521
|
+
firstSeenAt: number; // Timestamp (ms) when first observed
|
|
522
|
+
attachment: bigint[] | null; // Pre-decoded attachment values
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
463
526
|
#### `useAssetMetadata(assetIds)`
|
|
464
527
|
|
|
465
528
|
Fetch asset symbols/decimals for a list of asset IDs. This is the lightweight
|
|
@@ -507,6 +570,12 @@ It collapses the multi-step transaction pipeline into a single call with stage
|
|
|
507
570
|
tracking. You get private note delivery without having to remember the extra
|
|
508
571
|
send step.
|
|
509
572
|
|
|
573
|
+
Built-in features:
|
|
574
|
+
- **Auto pre-sync** before executing (disable with `skipSync: true`)
|
|
575
|
+
- **Concurrency guard** prevents double-sends while a transaction is in-flight
|
|
576
|
+
- **Attachment support** for sending arbitrary data with notes
|
|
577
|
+
- **`sendAll`** to send the full balance of an asset
|
|
578
|
+
|
|
510
579
|
```tsx
|
|
511
580
|
import { useSend } from '@miden-sdk/react';
|
|
512
581
|
|
|
@@ -529,8 +598,11 @@ function SendForm() {
|
|
|
529
598
|
amount: 100n, // Amount in smallest units
|
|
530
599
|
|
|
531
600
|
// Optional parameters
|
|
532
|
-
noteType: 'private', // 'private' | 'public'
|
|
601
|
+
noteType: 'private', // 'private' | 'public' (default: 'private')
|
|
533
602
|
recallHeight: 1000, // Sender can reclaim after this block
|
|
603
|
+
attachment: [1n, 2n, 3n], // Arbitrary data payload
|
|
604
|
+
skipSync: false, // Skip auto-sync before send (default: false)
|
|
605
|
+
sendAll: false, // Send full balance (ignores amount)
|
|
534
606
|
});
|
|
535
607
|
|
|
536
608
|
console.log('Sent! TX:', transactionId);
|
|
@@ -561,6 +633,11 @@ each note to recipients via `sendPrivateNote`.
|
|
|
561
633
|
It builds the request and executes the full pipeline in one go. That means
|
|
562
634
|
fewer chances to handle batching incorrectly or forget private note delivery.
|
|
563
635
|
|
|
636
|
+
Built-in features:
|
|
637
|
+
- **Auto pre-sync** before executing (disable with `skipSync: true`)
|
|
638
|
+
- **Concurrency guard** prevents double-sends while a transaction is in-flight
|
|
639
|
+
- **Per-recipient note type and attachment overrides**
|
|
640
|
+
|
|
564
641
|
```tsx
|
|
565
642
|
import { useMultiSend } from '@miden-sdk/react';
|
|
566
643
|
|
|
@@ -573,9 +650,10 @@ function MultiSendButton() {
|
|
|
573
650
|
assetId: '0xtoken...',
|
|
574
651
|
recipients: [
|
|
575
652
|
{ to: '0xrec1...', amount: 100n },
|
|
576
|
-
{ to: '0xrec2...', amount: 250n },
|
|
653
|
+
{ to: '0xrec2...', amount: 250n, attachment: [42n] },
|
|
577
654
|
],
|
|
578
|
-
noteType: 'public',
|
|
655
|
+
noteType: 'public', // Default for all recipients
|
|
656
|
+
skipSync: false, // Optional: skip auto-sync (default: false)
|
|
579
657
|
});
|
|
580
658
|
};
|
|
581
659
|
|
|
@@ -731,7 +809,7 @@ function MintForm() {
|
|
|
731
809
|
faucetId: '0xmyfaucet...', // Your faucet ID
|
|
732
810
|
targetAccountId: '0xwallet...', // Recipient wallet
|
|
733
811
|
amount: 1000n * 10n**8n, // Amount to mint
|
|
734
|
-
noteType: 'private', // Optional: 'private' | 'public'
|
|
812
|
+
noteType: 'private', // Optional: 'private' | 'public'
|
|
735
813
|
});
|
|
736
814
|
|
|
737
815
|
console.log('Minted! TX:', transactionId);
|
|
@@ -838,6 +916,10 @@ It standardizes the execute/prove/submit flow while still letting you craft the
|
|
|
838
916
|
request. You get progress and error handling without wrapping every call
|
|
839
917
|
yourself.
|
|
840
918
|
|
|
919
|
+
Built-in features:
|
|
920
|
+
- **Auto pre-sync** before executing (disable with `skipSync: true`)
|
|
921
|
+
- **Concurrency guard** prevents double-executions while a transaction is in-flight
|
|
922
|
+
|
|
841
923
|
```tsx
|
|
842
924
|
import { useTransaction } from '@miden-sdk/react';
|
|
843
925
|
import { AccountId, NoteType } from '@miden-sdk/miden-sdk';
|
|
@@ -858,6 +940,7 @@ function CustomTransactionButton({ accountId }: { accountId: string }) {
|
|
|
858
940
|
NoteType.Private,
|
|
859
941
|
NoteType.Private
|
|
860
942
|
),
|
|
943
|
+
skipSync: false, // Optional: skip auto-sync (default: false)
|
|
861
944
|
});
|
|
862
945
|
};
|
|
863
946
|
|
|
@@ -869,6 +952,152 @@ function CustomTransactionButton({ accountId }: { accountId: string }) {
|
|
|
869
952
|
}
|
|
870
953
|
```
|
|
871
954
|
|
|
955
|
+
#### `useSessionAccount(options)`
|
|
956
|
+
|
|
957
|
+
Manage a session wallet lifecycle: create, fund, and consume in a single flow.
|
|
958
|
+
Replaces the common 300+ line pattern of creating a temporary wallet, waiting
|
|
959
|
+
for funding, and consuming the funding note. Persists the session wallet ID
|
|
960
|
+
to localStorage for page reloads.
|
|
961
|
+
|
|
962
|
+
```tsx
|
|
963
|
+
import { useSessionAccount, useSend } from '@miden-sdk/react';
|
|
964
|
+
|
|
965
|
+
function SessionWallet({ mainWalletId, assetId }: { mainWalletId: string; assetId: string }) {
|
|
966
|
+
const { send } = useSend();
|
|
967
|
+
const { initialize, sessionAccountId, isReady, step, error, reset } =
|
|
968
|
+
useSessionAccount({
|
|
969
|
+
fund: async (sessionId) => {
|
|
970
|
+
// Send tokens from main wallet to session wallet
|
|
971
|
+
await send({ from: mainWalletId, to: sessionId, assetId, amount: 100n });
|
|
972
|
+
},
|
|
973
|
+
assetId,
|
|
974
|
+
// Optional:
|
|
975
|
+
// walletOptions: { storageMode: 'public', mutable: true, authScheme: 0 },
|
|
976
|
+
// pollIntervalMs: 3000,
|
|
977
|
+
// storagePrefix: 'miden-session',
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
if (error) return <div>Error: {error.message} <button onClick={reset}>Retry</button></div>;
|
|
981
|
+
if (isReady) return <div>Session ready: {sessionAccountId}</div>;
|
|
982
|
+
|
|
983
|
+
return (
|
|
984
|
+
<button onClick={initialize} disabled={step !== 'idle'}>
|
|
985
|
+
{step === 'idle' ? 'Start Session' : `${step}...`}
|
|
986
|
+
</button>
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
Steps: `idle` -> `creating` -> `funding` -> `consuming` -> `ready`
|
|
992
|
+
|
|
993
|
+
## Utilities
|
|
994
|
+
|
|
995
|
+
The SDK exports standalone utility functions for common tasks.
|
|
996
|
+
|
|
997
|
+
### Note Attachments
|
|
998
|
+
|
|
999
|
+
Read and write arbitrary data payloads on notes:
|
|
1000
|
+
|
|
1001
|
+
```typescript
|
|
1002
|
+
import { readNoteAttachment, createNoteAttachment } from '@miden-sdk/react';
|
|
1003
|
+
|
|
1004
|
+
// Read attachment from a note record
|
|
1005
|
+
const data = readNoteAttachment(noteRecord);
|
|
1006
|
+
if (data) {
|
|
1007
|
+
console.log(data.values); // bigint[]
|
|
1008
|
+
console.log(data.kind); // 'word' (<=4 values) or 'array' (>4 values)
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Create attachment for sending
|
|
1012
|
+
const attachment = createNoteAttachment([1n, 2n, 3n]);
|
|
1013
|
+
// <= 4 values -> Word (auto-padded to 4)
|
|
1014
|
+
// > 4 values -> Array (auto-padded to multiple of 4)
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
### Account ID Normalization
|
|
1018
|
+
|
|
1019
|
+
Compare and normalize account IDs across hex and bech32 formats:
|
|
1020
|
+
|
|
1021
|
+
```typescript
|
|
1022
|
+
import { normalizeAccountId, accountIdsEqual } from '@miden-sdk/react';
|
|
1023
|
+
|
|
1024
|
+
const bech32 = normalizeAccountId('0x1234...'); // Returns bech32 format
|
|
1025
|
+
accountIdsEqual('0x1234...', 'miden1abc...'); // true (format-agnostic)
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
### Byte Conversion
|
|
1029
|
+
|
|
1030
|
+
Utilities for bigint/byte conversions useful in cryptographic note data:
|
|
1031
|
+
|
|
1032
|
+
```typescript
|
|
1033
|
+
import { bytesToBigInt, bigIntToBytes, concatBytes } from '@miden-sdk/react';
|
|
1034
|
+
|
|
1035
|
+
const n = bytesToBigInt(new Uint8Array([0x01, 0x00])); // 256n
|
|
1036
|
+
const bytes = bigIntToBytes(256n, 2); // Uint8Array([0x01, 0x00])
|
|
1037
|
+
const combined = concatBytes(bytes1, bytes2); // Concatenated Uint8Array
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
### Storage Helpers
|
|
1041
|
+
|
|
1042
|
+
IndexedDB migration and namespaced localStorage persistence:
|
|
1043
|
+
|
|
1044
|
+
```typescript
|
|
1045
|
+
import { migrateStorage, clearMidenStorage, createMidenStorage } from '@miden-sdk/react';
|
|
1046
|
+
|
|
1047
|
+
// Auto-clear stale IndexedDB when SDK version changes
|
|
1048
|
+
await migrateStorage({
|
|
1049
|
+
version: '0.13.1',
|
|
1050
|
+
// versionKey: 'miden:storageVersion', // default
|
|
1051
|
+
// reloadOnClear: true, // default
|
|
1052
|
+
// onBeforeClear: () => { /* save data */ },
|
|
1053
|
+
});
|
|
1054
|
+
|
|
1055
|
+
// Namespaced localStorage for app state
|
|
1056
|
+
const store = createMidenStorage('myapp');
|
|
1057
|
+
store.set('lastOpponent', '0x1234...');
|
|
1058
|
+
const opponent = store.get<string>('lastOpponent');
|
|
1059
|
+
store.remove('lastOpponent');
|
|
1060
|
+
store.clear(); // Clears only keys under 'myapp:' prefix
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
### Wallet Detection
|
|
1064
|
+
|
|
1065
|
+
Wait for a browser extension wallet to be detected before connecting:
|
|
1066
|
+
|
|
1067
|
+
```typescript
|
|
1068
|
+
import { waitForWalletDetection } from '@miden-sdk/react';
|
|
1069
|
+
|
|
1070
|
+
const adapter = wallets[0].adapter;
|
|
1071
|
+
|
|
1072
|
+
// Default 5s timeout
|
|
1073
|
+
await waitForWalletDetection(adapter);
|
|
1074
|
+
|
|
1075
|
+
// Custom timeout
|
|
1076
|
+
await waitForWalletDetection(adapter, 10000);
|
|
1077
|
+
|
|
1078
|
+
// Returns immediately if already installed, otherwise
|
|
1079
|
+
// listens for readyStateChange events with a timeout.
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
This replaces the common 30-line polling+timeout pattern needed when the wallet extension loads slowly. The adapter is duck-typed — any object with `readyState`, `on("readyStateChange", ...)`, and `off("readyStateChange", ...)` will work.
|
|
1083
|
+
|
|
1084
|
+
### Error Handling Utilities
|
|
1085
|
+
|
|
1086
|
+
WASM errors are cryptic. The SDK wraps common patterns with actionable messages:
|
|
1087
|
+
|
|
1088
|
+
```typescript
|
|
1089
|
+
import { MidenError, wrapWasmError } from '@miden-sdk/react';
|
|
1090
|
+
|
|
1091
|
+
try {
|
|
1092
|
+
await client.someMethod(accountId);
|
|
1093
|
+
} catch (e) {
|
|
1094
|
+
const wrapped = wrapWasmError(e);
|
|
1095
|
+
// MidenError with code: 'WASM_CLASS_MISMATCH' | 'WASM_POINTER_CONSUMED' |
|
|
1096
|
+
// 'WASM_NOT_INITIALIZED' | 'WASM_SYNC_REQUIRED' | 'SEND_BUSY' | 'UNKNOWN'
|
|
1097
|
+
console.log(wrapped.message); // Human-readable with fix suggestions
|
|
1098
|
+
}
|
|
1099
|
+
```
|
|
1100
|
+
|
|
872
1101
|
## Common Patterns
|
|
873
1102
|
|
|
874
1103
|
### Error Handling
|
|
@@ -948,6 +1177,157 @@ function MyFeature() {
|
|
|
948
1177
|
}
|
|
949
1178
|
```
|
|
950
1179
|
|
|
1180
|
+
## External Signer Integration
|
|
1181
|
+
|
|
1182
|
+
For wallets using external key management, wrap your app with a signer provider **above** `MidenProvider`. The signer provider populates a `SignerContext` with a `signCb` and an `accountConfig`; `MidenProvider` picks these up automatically to create the client and initialize the account.
|
|
1183
|
+
|
|
1184
|
+
### Para (EVM Wallets)
|
|
1185
|
+
|
|
1186
|
+
```tsx
|
|
1187
|
+
import { ParaSignerProvider } from '@miden-sdk/para';
|
|
1188
|
+
|
|
1189
|
+
function App() {
|
|
1190
|
+
return (
|
|
1191
|
+
<ParaSignerProvider apiKey="your-api-key" environment="PRODUCTION">
|
|
1192
|
+
<MidenProvider config={{ rpcUrl: 'testnet' }}>
|
|
1193
|
+
<YourApp />
|
|
1194
|
+
</MidenProvider>
|
|
1195
|
+
</ParaSignerProvider>
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// Access Para-specific data
|
|
1200
|
+
const { para, wallet, isConnected } = useParaSigner();
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
### Turnkey
|
|
1204
|
+
|
|
1205
|
+
```tsx
|
|
1206
|
+
import { TurnkeySignerProvider } from '@miden-sdk/miden-turnkey-react';
|
|
1207
|
+
|
|
1208
|
+
function App() {
|
|
1209
|
+
return (
|
|
1210
|
+
// Config is optional — defaults to https://api.turnkey.com
|
|
1211
|
+
// and reads VITE_TURNKEY_ORG_ID from environment
|
|
1212
|
+
<TurnkeySignerProvider>
|
|
1213
|
+
<MidenProvider config={{ rpcUrl: 'testnet' }}>
|
|
1214
|
+
<YourApp />
|
|
1215
|
+
</MidenProvider>
|
|
1216
|
+
</TurnkeySignerProvider>
|
|
1217
|
+
);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// Or with explicit config:
|
|
1221
|
+
<TurnkeySignerProvider config={{
|
|
1222
|
+
apiBaseUrl: 'https://api.turnkey.com',
|
|
1223
|
+
defaultOrganizationId: 'your-org-id',
|
|
1224
|
+
}}>
|
|
1225
|
+
...
|
|
1226
|
+
</TurnkeySignerProvider>
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
Connect via passkey authentication:
|
|
1230
|
+
|
|
1231
|
+
```tsx
|
|
1232
|
+
import { useSigner } from '@miden-sdk/react';
|
|
1233
|
+
import { useTurnkeySigner } from '@miden-sdk/miden-turnkey-react';
|
|
1234
|
+
|
|
1235
|
+
const { isConnected, connect, disconnect } = useSigner();
|
|
1236
|
+
await connect(); // triggers passkey flow
|
|
1237
|
+
|
|
1238
|
+
const { client, account, setAccount } = useTurnkeySigner();
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
### MidenFi Wallet Adapter
|
|
1242
|
+
|
|
1243
|
+
```tsx
|
|
1244
|
+
import { MidenFiSignerProvider } from '@miden-sdk/wallet-adapter-react';
|
|
1245
|
+
|
|
1246
|
+
function App() {
|
|
1247
|
+
return (
|
|
1248
|
+
<MidenFiSignerProvider network="Testnet">
|
|
1249
|
+
<MidenProvider config={{ rpcUrl: 'testnet' }}>
|
|
1250
|
+
<YourApp />
|
|
1251
|
+
</MidenProvider>
|
|
1252
|
+
</MidenFiSignerProvider>
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
### Unified Signer Hook
|
|
1258
|
+
|
|
1259
|
+
`useSigner()` works with any signer provider:
|
|
1260
|
+
|
|
1261
|
+
```tsx
|
|
1262
|
+
import { useSigner } from '@miden-sdk/react';
|
|
1263
|
+
|
|
1264
|
+
function ConnectButton() {
|
|
1265
|
+
const signer = useSigner();
|
|
1266
|
+
if (!signer) return null; // local keystore mode
|
|
1267
|
+
|
|
1268
|
+
const { isConnected, connect, disconnect, name } = signer;
|
|
1269
|
+
return isConnected
|
|
1270
|
+
? <button onClick={disconnect}>Disconnect {name}</button>
|
|
1271
|
+
: <button onClick={connect}>Connect with {name}</button>;
|
|
1272
|
+
}
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
### Custom Account Components
|
|
1276
|
+
|
|
1277
|
+
Signer providers can include custom `AccountComponent` instances in the account via the `customComponents` field on `SignerAccountConfig`. This is useful for attaching application-specific logic compiled from `.masp` packages (e.g. a DEX component or custom smart contract) alongside the default auth and basic wallet components.
|
|
1278
|
+
|
|
1279
|
+
Pre-built signer providers (Para, Turnkey, MidenFi) accept `customComponents` as a prop and forward it into `accountConfig`:
|
|
1280
|
+
|
|
1281
|
+
```tsx
|
|
1282
|
+
import { ParaSignerProvider } from '@miden-sdk/para';
|
|
1283
|
+
import type { AccountComponent } from '@miden-sdk/miden-sdk';
|
|
1284
|
+
|
|
1285
|
+
const dexComponent: AccountComponent = await loadCompiledComponent();
|
|
1286
|
+
|
|
1287
|
+
<ParaSignerProvider
|
|
1288
|
+
apiKey="your-api-key"
|
|
1289
|
+
environment="PRODUCTION"
|
|
1290
|
+
customComponents={[dexComponent]}
|
|
1291
|
+
>
|
|
1292
|
+
<MidenProvider config={{ rpcUrl: 'testnet' }}>
|
|
1293
|
+
<YourApp />
|
|
1294
|
+
</MidenProvider>
|
|
1295
|
+
</ParaSignerProvider>
|
|
1296
|
+
```
|
|
1297
|
+
|
|
1298
|
+
When building a custom signer provider, pass `customComponents` through the `SignerContext` directly:
|
|
1299
|
+
|
|
1300
|
+
```tsx
|
|
1301
|
+
import { SignerContext } from '@miden-sdk/react';
|
|
1302
|
+
import type { AccountComponent } from '@miden-sdk/miden-sdk';
|
|
1303
|
+
|
|
1304
|
+
function MySignerProvider({ children, customComponents }: {
|
|
1305
|
+
children: React.ReactNode;
|
|
1306
|
+
customComponents?: AccountComponent[];
|
|
1307
|
+
}) {
|
|
1308
|
+
return (
|
|
1309
|
+
<SignerContext.Provider value={{
|
|
1310
|
+
name: 'MySigner',
|
|
1311
|
+
storeName: `mysigner_${userId}`,
|
|
1312
|
+
isConnected: true,
|
|
1313
|
+
accountConfig: {
|
|
1314
|
+
publicKeyCommitment: userPublicKeyCommitment,
|
|
1315
|
+
accountType: 'RegularAccountUpdatableCode',
|
|
1316
|
+
storageMode: myStorageMode,
|
|
1317
|
+
customComponents,
|
|
1318
|
+
},
|
|
1319
|
+
signCb: async (pubKey, signingInputs) => signature,
|
|
1320
|
+
connect: async () => { /* ... */ },
|
|
1321
|
+
disconnect: async () => { /* ... */ },
|
|
1322
|
+
}}>
|
|
1323
|
+
{children}
|
|
1324
|
+
</SignerContext.Provider>
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
```
|
|
1328
|
+
|
|
1329
|
+
Components are appended to the `AccountBuilder` after the default basic wallet component and before `build()` is called, so the account always includes wallet functionality plus any extras you provide. The field is optional — omitting it or passing an empty array preserves the default behavior.
|
|
1330
|
+
|
|
951
1331
|
## Default Values
|
|
952
1332
|
|
|
953
1333
|
The SDK uses privacy-first defaults:
|
|
@@ -957,7 +1337,8 @@ The SDK uses privacy-first defaults:
|
|
|
957
1337
|
| `storageMode` | `'private'` | Account data stored off-chain |
|
|
958
1338
|
| `mutable` | `true` | Wallet code can be updated |
|
|
959
1339
|
| `authScheme` | `0` (Falcon) | Post-quantum secure signatures |
|
|
960
|
-
| `noteType` | `'private'` | Note contents
|
|
1340
|
+
| `noteType` | `'private'` | Note contents are private |
|
|
1341
|
+
| `skipSync` | `false` | Auto-sync before transactions |
|
|
961
1342
|
| `decimals` | `8` | Token decimal places |
|
|
962
1343
|
| `autoSyncInterval` | `15000` | Sync every 15 seconds |
|
|
963
1344
|
|
|
@@ -988,6 +1369,16 @@ import type {
|
|
|
988
1369
|
ExecuteTransactionOptions,
|
|
989
1370
|
NotesFilter,
|
|
990
1371
|
|
|
1372
|
+
// Note stream types
|
|
1373
|
+
StreamedNote,
|
|
1374
|
+
UseNoteStreamOptions,
|
|
1375
|
+
UseNoteStreamReturn,
|
|
1376
|
+
|
|
1377
|
+
// Session account types
|
|
1378
|
+
UseSessionAccountOptions,
|
|
1379
|
+
UseSessionAccountReturn,
|
|
1380
|
+
SessionAccountStep,
|
|
1381
|
+
|
|
991
1382
|
// Hook results
|
|
992
1383
|
AccountResult,
|
|
993
1384
|
AccountsResult,
|
|
@@ -998,6 +1389,11 @@ import type {
|
|
|
998
1389
|
TransactionStage,
|
|
999
1390
|
AssetBalance,
|
|
1000
1391
|
SyncState,
|
|
1392
|
+
|
|
1393
|
+
// Utility types
|
|
1394
|
+
NoteAttachmentData,
|
|
1395
|
+
MidenErrorCode,
|
|
1396
|
+
MigrateStorageOptions,
|
|
1001
1397
|
} from '@miden-sdk/react';
|
|
1002
1398
|
```
|
|
1003
1399
|
|
|
@@ -1016,7 +1412,7 @@ yarn dev
|
|
|
1016
1412
|
## Requirements
|
|
1017
1413
|
|
|
1018
1414
|
- React 18.0 or higher
|
|
1019
|
-
- `@miden-sdk/miden-sdk` ^0.13.
|
|
1415
|
+
- `@miden-sdk/miden-sdk` ^0.13.1
|
|
1020
1416
|
|
|
1021
1417
|
## Browser Support
|
|
1022
1418
|
|