@mysten-incubation/dev-wallet 0.0.0
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 +250 -0
- package/dist/_virtual/_@oxc-project_runtime@0.107.0/helpers/decorate.mjs +10 -0
- package/dist/adapters/base-adapter.d.mts +33 -0
- package/dist/adapters/base-adapter.d.mts.map +1 -0
- package/dist/adapters/base-adapter.mjs +77 -0
- package/dist/adapters/base-adapter.mjs.map +1 -0
- package/dist/adapters/browser.d.mts +8 -0
- package/dist/adapters/browser.mjs +8 -0
- package/dist/adapters/build-managed-account.d.mts +12 -0
- package/dist/adapters/build-managed-account.d.mts.map +1 -0
- package/dist/adapters/build-managed-account.mjs +30 -0
- package/dist/adapters/build-managed-account.mjs.map +1 -0
- package/dist/adapters/idb-store.mjs +73 -0
- package/dist/adapters/idb-store.mjs.map +1 -0
- package/dist/adapters/in-memory-adapter.d.mts +16 -0
- package/dist/adapters/in-memory-adapter.d.mts.map +1 -0
- package/dist/adapters/in-memory-adapter.mjs +44 -0
- package/dist/adapters/in-memory-adapter.mjs.map +1 -0
- package/dist/adapters/passkey-adapter.d.mts +31 -0
- package/dist/adapters/passkey-adapter.d.mts.map +1 -0
- package/dist/adapters/passkey-adapter.mjs +87 -0
- package/dist/adapters/passkey-adapter.mjs.map +1 -0
- package/dist/adapters/remote-cli-adapter.d.mts +65 -0
- package/dist/adapters/remote-cli-adapter.d.mts.map +1 -0
- package/dist/adapters/remote-cli-adapter.mjs +299 -0
- package/dist/adapters/remote-cli-adapter.mjs.map +1 -0
- package/dist/adapters/webcrypto-adapter.d.mts +20 -0
- package/dist/adapters/webcrypto-adapter.d.mts.map +1 -0
- package/dist/adapters/webcrypto-adapter.mjs +68 -0
- package/dist/adapters/webcrypto-adapter.mjs.map +1 -0
- package/dist/bin/cli.d.mts +1 -0
- package/dist/bin/cli.mjs +183 -0
- package/dist/bin/cli.mjs.map +1 -0
- package/dist/client/dev-wallet-client.d.mts +57 -0
- package/dist/client/dev-wallet-client.d.mts.map +1 -0
- package/dist/client/dev-wallet-client.mjs +223 -0
- package/dist/client/dev-wallet-client.mjs.map +1 -0
- package/dist/client/index.d.mts +3 -0
- package/dist/client/index.mjs +4 -0
- package/dist/client/request-handler.d.mts +42 -0
- package/dist/client/request-handler.d.mts.map +1 -0
- package/dist/client/request-handler.mjs +115 -0
- package/dist/client/request-handler.mjs.map +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +4 -0
- package/dist/react/components.d.mts +32 -0
- package/dist/react/components.d.mts.map +1 -0
- package/dist/react/components.mjs +53 -0
- package/dist/react/components.mjs.map +1 -0
- package/dist/react/context.d.mts +22 -0
- package/dist/react/context.d.mts.map +1 -0
- package/dist/react/context.mjs +25 -0
- package/dist/react/context.mjs.map +1 -0
- package/dist/react/index.d.mts +4 -0
- package/dist/react/index.mjs +5 -0
- package/dist/react/useDevWallet.d.mts +38 -0
- package/dist/react/useDevWallet.d.mts.map +1 -0
- package/dist/react/useDevWallet.mjs +89 -0
- package/dist/react/useDevWallet.mjs.map +1 -0
- package/dist/server/cli-signing-middleware.d.mts +22 -0
- package/dist/server/cli-signing-middleware.d.mts.map +1 -0
- package/dist/server/cli-signing-middleware.mjs +117 -0
- package/dist/server/cli-signing-middleware.mjs.map +1 -0
- package/dist/server/index.d.mts +2 -0
- package/dist/server/index.mjs +3 -0
- package/dist/standalone/assets/in-memory-adapter-CBF4h2KD.js +1 -0
- package/dist/standalone/assets/main-VE4olb-Q.js +2841 -0
- package/dist/standalone/assets/webcrypto-adapter-DysAubFb.js +1 -0
- package/dist/standalone/bookmarklet.js +5 -0
- package/dist/standalone/index.html +48 -0
- package/dist/types.d.mts +55 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/ui/copy-controller.mjs +43 -0
- package/dist/ui/copy-controller.mjs.map +1 -0
- package/dist/ui/dev-wallet-account-selector.d.mts +24 -0
- package/dist/ui/dev-wallet-account-selector.d.mts.map +1 -0
- package/dist/ui/dev-wallet-account-selector.mjs +268 -0
- package/dist/ui/dev-wallet-account-selector.mjs.map +1 -0
- package/dist/ui/dev-wallet-accounts.d.mts +29 -0
- package/dist/ui/dev-wallet-accounts.d.mts.map +1 -0
- package/dist/ui/dev-wallet-accounts.mjs +524 -0
- package/dist/ui/dev-wallet-accounts.mjs.map +1 -0
- package/dist/ui/dev-wallet-balances.d.mts +26 -0
- package/dist/ui/dev-wallet-balances.d.mts.map +1 -0
- package/dist/ui/dev-wallet-balances.mjs +130 -0
- package/dist/ui/dev-wallet-balances.mjs.map +1 -0
- package/dist/ui/dev-wallet-connect.d.mts +31 -0
- package/dist/ui/dev-wallet-connect.d.mts.map +1 -0
- package/dist/ui/dev-wallet-connect.mjs +225 -0
- package/dist/ui/dev-wallet-connect.mjs.map +1 -0
- package/dist/ui/dev-wallet-dropdown.d.mts +27 -0
- package/dist/ui/dev-wallet-dropdown.d.mts.map +1 -0
- package/dist/ui/dev-wallet-dropdown.mjs +121 -0
- package/dist/ui/dev-wallet-dropdown.mjs.map +1 -0
- package/dist/ui/dev-wallet-network-badge.d.mts +21 -0
- package/dist/ui/dev-wallet-network-badge.d.mts.map +1 -0
- package/dist/ui/dev-wallet-network-badge.mjs +121 -0
- package/dist/ui/dev-wallet-network-badge.mjs.map +1 -0
- package/dist/ui/dev-wallet-new-account.d.mts +31 -0
- package/dist/ui/dev-wallet-new-account.d.mts.map +1 -0
- package/dist/ui/dev-wallet-new-account.mjs +577 -0
- package/dist/ui/dev-wallet-new-account.mjs.map +1 -0
- package/dist/ui/dev-wallet-objects.d.mts +26 -0
- package/dist/ui/dev-wallet-objects.d.mts.map +1 -0
- package/dist/ui/dev-wallet-objects.mjs +276 -0
- package/dist/ui/dev-wallet-objects.mjs.map +1 -0
- package/dist/ui/dev-wallet-panel.d.mts +22 -0
- package/dist/ui/dev-wallet-panel.d.mts.map +1 -0
- package/dist/ui/dev-wallet-panel.mjs +192 -0
- package/dist/ui/dev-wallet-panel.mjs.map +1 -0
- package/dist/ui/dev-wallet-popup.d.mts +36 -0
- package/dist/ui/dev-wallet-popup.d.mts.map +1 -0
- package/dist/ui/dev-wallet-popup.mjs +137 -0
- package/dist/ui/dev-wallet-popup.mjs.map +1 -0
- package/dist/ui/dev-wallet-settings.d.mts +33 -0
- package/dist/ui/dev-wallet-settings.d.mts.map +1 -0
- package/dist/ui/dev-wallet-settings.mjs +635 -0
- package/dist/ui/dev-wallet-settings.mjs.map +1 -0
- package/dist/ui/dev-wallet-signing-modal.d.mts +32 -0
- package/dist/ui/dev-wallet-signing-modal.d.mts.map +1 -0
- package/dist/ui/dev-wallet-signing-modal.mjs +115 -0
- package/dist/ui/dev-wallet-signing-modal.mjs.map +1 -0
- package/dist/ui/dev-wallet-signing.d.mts +25 -0
- package/dist/ui/dev-wallet-signing.d.mts.map +1 -0
- package/dist/ui/dev-wallet-signing.mjs +544 -0
- package/dist/ui/dev-wallet-signing.mjs.map +1 -0
- package/dist/ui/dev-wallet-standalone.d.mts +23 -0
- package/dist/ui/dev-wallet-standalone.d.mts.map +1 -0
- package/dist/ui/dev-wallet-standalone.mjs +129 -0
- package/dist/ui/dev-wallet-standalone.mjs.map +1 -0
- package/dist/ui/dev-wallet-tab-bar.d.mts +19 -0
- package/dist/ui/dev-wallet-tab-bar.d.mts.map +1 -0
- package/dist/ui/dev-wallet-tab-bar.mjs +143 -0
- package/dist/ui/dev-wallet-tab-bar.mjs.map +1 -0
- package/dist/ui/index.d.mts +17 -0
- package/dist/ui/index.mjs +18 -0
- package/dist/ui/mount.d.mts +11 -0
- package/dist/ui/mount.d.mts.map +1 -0
- package/dist/ui/mount.mjs +17 -0
- package/dist/ui/mount.mjs.map +1 -0
- package/dist/ui/styles.mjs +250 -0
- package/dist/ui/styles.mjs.map +1 -0
- package/dist/ui/transaction-analyzer.mjs +58 -0
- package/dist/ui/transaction-analyzer.mjs.map +1 -0
- package/dist/ui/utils.mjs +98 -0
- package/dist/ui/utils.mjs.map +1 -0
- package/dist/ui/wallet-controller.mjs +275 -0
- package/dist/ui/wallet-controller.mjs.map +1 -0
- package/dist/wallet/constants.mjs +11 -0
- package/dist/wallet/constants.mjs.map +1 -0
- package/dist/wallet/dev-wallet.d.mts +118 -0
- package/dist/wallet/dev-wallet.d.mts.map +1 -0
- package/dist/wallet/dev-wallet.mjs +424 -0
- package/dist/wallet/dev-wallet.mjs.map +1 -0
- package/dist/wallet/initializer.d.mts +63 -0
- package/dist/wallet/initializer.d.mts.map +1 -0
- package/dist/wallet/initializer.mjs +75 -0
- package/dist/wallet/initializer.mjs.map +1 -0
- package/dist/wallet/signing.d.mts +35 -0
- package/dist/wallet/signing.d.mts.map +1 -0
- package/dist/wallet/signing.mjs +69 -0
- package/dist/wallet/signing.mjs.map +1 -0
- package/package.json +124 -0
- package/src/adapters/base-adapter.ts +93 -0
- package/src/adapters/browser.ts +15 -0
- package/src/adapters/build-managed-account.ts +33 -0
- package/src/adapters/idb-store.ts +87 -0
- package/src/adapters/in-memory-adapter.ts +51 -0
- package/src/adapters/passkey-adapter.ts +120 -0
- package/src/adapters/remote-cli-adapter.ts +388 -0
- package/src/adapters/webcrypto-adapter.ts +96 -0
- package/src/app/bookmarklet-entry.ts +77 -0
- package/src/app/index.html +48 -0
- package/src/app/main.ts +245 -0
- package/src/app/tsconfig.json +3 -0
- package/src/bin/cli.ts +214 -0
- package/src/client/dev-wallet-client.ts +280 -0
- package/src/client/index.ts +7 -0
- package/src/client/request-handler.ts +161 -0
- package/src/index.ts +19 -0
- package/src/react/components.ts +64 -0
- package/src/react/context.ts +38 -0
- package/src/react/index.ts +16 -0
- package/src/react/useDevWallet.ts +118 -0
- package/src/server/cli-signing-middleware.ts +146 -0
- package/src/server/index.ts +8 -0
- package/src/types.ts +58 -0
- package/src/ui/copy-controller.ts +49 -0
- package/src/ui/dev-wallet-account-selector.ts +283 -0
- package/src/ui/dev-wallet-accounts.ts +578 -0
- package/src/ui/dev-wallet-balances.ts +171 -0
- package/src/ui/dev-wallet-connect.ts +259 -0
- package/src/ui/dev-wallet-dropdown.ts +138 -0
- package/src/ui/dev-wallet-network-badge.ts +128 -0
- package/src/ui/dev-wallet-new-account.ts +662 -0
- package/src/ui/dev-wallet-objects.ts +336 -0
- package/src/ui/dev-wallet-panel.ts +207 -0
- package/src/ui/dev-wallet-popup.ts +169 -0
- package/src/ui/dev-wallet-settings.ts +692 -0
- package/src/ui/dev-wallet-signing-modal.ts +137 -0
- package/src/ui/dev-wallet-signing.ts +624 -0
- package/src/ui/dev-wallet-standalone.ts +136 -0
- package/src/ui/dev-wallet-tab-bar.ts +151 -0
- package/src/ui/index.ts +26 -0
- package/src/ui/mount.ts +21 -0
- package/src/ui/styles.ts +252 -0
- package/src/ui/transaction-analyzer.ts +60 -0
- package/src/ui/utils.ts +118 -0
- package/src/ui/wallet-controller.ts +340 -0
- package/src/wallet/constants.ts +17 -0
- package/src/wallet/dev-wallet.ts +597 -0
- package/src/wallet/initializer.ts +124 -0
- package/src/wallet/signing.ts +85 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { fromBase64, toBase64 } from '@mysten/sui/utils';
|
|
5
|
+
import { mitt, type Emitter } from '@mysten/utils';
|
|
6
|
+
import type {
|
|
7
|
+
StandardConnectFeature,
|
|
8
|
+
StandardConnectMethod,
|
|
9
|
+
StandardDisconnectFeature,
|
|
10
|
+
StandardDisconnectMethod,
|
|
11
|
+
StandardEventsFeature,
|
|
12
|
+
StandardEventsOnMethod,
|
|
13
|
+
SuiFeatures,
|
|
14
|
+
SuiSignAndExecuteTransactionMethod,
|
|
15
|
+
SuiSignPersonalMessageMethod,
|
|
16
|
+
SuiSignTransactionMethod,
|
|
17
|
+
Wallet,
|
|
18
|
+
WalletIcon,
|
|
19
|
+
} from '@mysten/wallet-standard';
|
|
20
|
+
import { getWallets, ReadonlyWalletAccount, SUI_CHAINS } from '@mysten/wallet-standard';
|
|
21
|
+
import { DappPostMessageChannel, decodeJwtSession } from '@mysten/window-wallet-core';
|
|
22
|
+
|
|
23
|
+
import { DEFAULT_WALLET_ICON, type WalletEventsMap } from '../wallet/constants.js';
|
|
24
|
+
|
|
25
|
+
const DEFAULT_WALLET_NAME = 'Dev Wallet (Web)';
|
|
26
|
+
const DEFAULT_ORIGIN = 'http://localhost:5174';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a wallet initializer that can be passed to `createDAppKit({ walletInitializers: [...] })`.
|
|
30
|
+
*
|
|
31
|
+
* This registers a {@link DevWalletClient} that communicates with a standalone
|
|
32
|
+
* dev wallet server via PostMessage popups.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { createDAppKit } from '@mysten/dapp-kit-react';
|
|
37
|
+
* import { devWalletClientInitializer } from '@mysten-incubation/dev-wallet/client';
|
|
38
|
+
*
|
|
39
|
+
* const dAppKit = createDAppKit({
|
|
40
|
+
* networks: ['devnet'],
|
|
41
|
+
* walletInitializers: [
|
|
42
|
+
* devWalletClientInitializer({ origin: 'http://localhost:5174' }),
|
|
43
|
+
* ],
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function devWalletClientInitializer(options?: DevWalletClientOptions): {
|
|
48
|
+
id: string;
|
|
49
|
+
initialize(): { unregister: () => void };
|
|
50
|
+
} {
|
|
51
|
+
return {
|
|
52
|
+
id: 'dev-wallet-client-initializer',
|
|
53
|
+
initialize() {
|
|
54
|
+
const unregister = DevWalletClient.register(options);
|
|
55
|
+
return { unregister };
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const WALLET_FEATURES = [
|
|
61
|
+
'sui:signTransaction',
|
|
62
|
+
'sui:signAndExecuteTransaction',
|
|
63
|
+
'sui:signPersonalMessage',
|
|
64
|
+
] as const;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Options for creating a DevWalletClient.
|
|
68
|
+
*/
|
|
69
|
+
export interface DevWalletClientOptions {
|
|
70
|
+
/** Display name for the wallet. Defaults to 'Dev Wallet (Web)'. */
|
|
71
|
+
name?: string;
|
|
72
|
+
/** Data URI icon for the wallet. */
|
|
73
|
+
icon?: WalletIcon;
|
|
74
|
+
/** Origin of the dev wallet web app. Defaults to 'http://localhost:5174'. */
|
|
75
|
+
origin?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Wallet-standard wallet that communicates with a standalone DevWallet
|
|
80
|
+
* web app via PostMessage popups (started via `npx @mysten-incubation/dev-wallet serve`).
|
|
81
|
+
*/
|
|
82
|
+
export class DevWalletClient implements Wallet {
|
|
83
|
+
readonly #name: string;
|
|
84
|
+
readonly #icon: WalletIcon;
|
|
85
|
+
readonly #origin: string;
|
|
86
|
+
readonly #sessionKey: string;
|
|
87
|
+
#accounts: ReadonlyWalletAccount[] = [];
|
|
88
|
+
#events: Emitter<WalletEventsMap>;
|
|
89
|
+
|
|
90
|
+
constructor(options?: DevWalletClientOptions) {
|
|
91
|
+
this.#name = options?.name ?? DEFAULT_WALLET_NAME;
|
|
92
|
+
this.#icon = options?.icon ?? DEFAULT_WALLET_ICON;
|
|
93
|
+
this.#origin = options?.origin ?? DEFAULT_ORIGIN;
|
|
94
|
+
this.#sessionKey = `dev-wallet:session:${this.#origin}`;
|
|
95
|
+
this.#events = mitt();
|
|
96
|
+
this.#tryRestoreSession();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static register(options?: DevWalletClientOptions): () => void {
|
|
100
|
+
const wallet = new DevWalletClient(options);
|
|
101
|
+
const wallets = getWallets();
|
|
102
|
+
return wallets.register(wallet);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get version() {
|
|
106
|
+
return '1.0.0' as const;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get name() {
|
|
110
|
+
return this.#name;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get icon() {
|
|
114
|
+
return this.#icon;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
get chains() {
|
|
118
|
+
return SUI_CHAINS;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get accounts(): readonly ReadonlyWalletAccount[] {
|
|
122
|
+
return this.#accounts;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
get features(): StandardConnectFeature &
|
|
126
|
+
StandardEventsFeature &
|
|
127
|
+
StandardDisconnectFeature &
|
|
128
|
+
SuiFeatures {
|
|
129
|
+
return {
|
|
130
|
+
'standard:connect': {
|
|
131
|
+
version: '1.0.0',
|
|
132
|
+
connect: this.#connect,
|
|
133
|
+
},
|
|
134
|
+
'standard:events': {
|
|
135
|
+
version: '1.0.0',
|
|
136
|
+
on: this.#on,
|
|
137
|
+
},
|
|
138
|
+
'standard:disconnect': {
|
|
139
|
+
version: '1.0.0',
|
|
140
|
+
disconnect: this.#disconnect,
|
|
141
|
+
},
|
|
142
|
+
'sui:signPersonalMessage': {
|
|
143
|
+
version: '1.1.0',
|
|
144
|
+
signPersonalMessage: this.#signPersonalMessage,
|
|
145
|
+
},
|
|
146
|
+
'sui:signTransaction': {
|
|
147
|
+
version: '2.0.0',
|
|
148
|
+
signTransaction: this.#signTransaction,
|
|
149
|
+
},
|
|
150
|
+
'sui:signAndExecuteTransaction': {
|
|
151
|
+
version: '2.0.0',
|
|
152
|
+
signAndExecuteTransaction: this.#signAndExecuteTransaction,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
#on: StandardEventsOnMethod = (event, listener) => {
|
|
158
|
+
this.#events.on(event, listener);
|
|
159
|
+
return () => this.#events.off(event, listener);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
#connect: StandardConnectMethod = async () => {
|
|
163
|
+
const channel = this.#createChannel();
|
|
164
|
+
const response = await channel.send({ type: 'connect' });
|
|
165
|
+
|
|
166
|
+
this.#setSession(response.session);
|
|
167
|
+
this.#setAccountsFromSession(response.session);
|
|
168
|
+
|
|
169
|
+
return { accounts: this.accounts };
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
#disconnect: StandardDisconnectMethod = async () => {
|
|
173
|
+
this.#clearSession();
|
|
174
|
+
this.#accounts = [];
|
|
175
|
+
this.#events.emit('change', { accounts: this.#accounts });
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
#signPersonalMessage: SuiSignPersonalMessageMethod = async (input) => {
|
|
179
|
+
const channel = this.#createChannel();
|
|
180
|
+
const response = await channel.send({
|
|
181
|
+
type: 'sign-personal-message',
|
|
182
|
+
message: toBase64(input.message),
|
|
183
|
+
address: input.account.address,
|
|
184
|
+
chain: input.chain ?? input.account.chains[0] ?? 'sui:unknown',
|
|
185
|
+
session: this.#getSession(),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return { bytes: response.bytes, signature: response.signature };
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
#signTransaction: SuiSignTransactionMethod = async (input) => {
|
|
192
|
+
const txJson = await input.transaction.toJSON();
|
|
193
|
+
const channel = this.#createChannel();
|
|
194
|
+
const response = await channel.send({
|
|
195
|
+
type: 'sign-transaction',
|
|
196
|
+
transaction: txJson,
|
|
197
|
+
address: input.account.address,
|
|
198
|
+
chain: input.chain,
|
|
199
|
+
session: this.#getSession(),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return { bytes: response.bytes, signature: response.signature };
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
#signAndExecuteTransaction: SuiSignAndExecuteTransactionMethod = async (input) => {
|
|
206
|
+
const txJson = await input.transaction.toJSON();
|
|
207
|
+
const channel = this.#createChannel();
|
|
208
|
+
const response = await channel.send({
|
|
209
|
+
type: 'sign-and-execute-transaction',
|
|
210
|
+
transaction: txJson,
|
|
211
|
+
address: input.account.address,
|
|
212
|
+
chain: input.chain,
|
|
213
|
+
session: this.#getSession(),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
bytes: response.bytes,
|
|
218
|
+
signature: response.signature,
|
|
219
|
+
digest: response.digest,
|
|
220
|
+
effects: response.effects,
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
#createChannel(): DappPostMessageChannel {
|
|
225
|
+
return new DappPostMessageChannel({
|
|
226
|
+
appName: this.#name,
|
|
227
|
+
hostOrigin: this.#origin,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#getSession(): string {
|
|
232
|
+
if (typeof localStorage === 'undefined') {
|
|
233
|
+
throw new Error('No active session. Call connect() first.');
|
|
234
|
+
}
|
|
235
|
+
const session = localStorage.getItem(this.#sessionKey);
|
|
236
|
+
if (!session) {
|
|
237
|
+
throw new Error('No active session. Call connect() first.');
|
|
238
|
+
}
|
|
239
|
+
return session;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
#setSession(session: string): void {
|
|
243
|
+
if (typeof localStorage !== 'undefined') {
|
|
244
|
+
localStorage.setItem(this.#sessionKey, session);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#clearSession(): void {
|
|
249
|
+
if (typeof localStorage !== 'undefined') {
|
|
250
|
+
localStorage.removeItem(this.#sessionKey);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
#setAccountsFromSession(session: string): void {
|
|
255
|
+
const decoded = decodeJwtSession(session);
|
|
256
|
+
this.#accounts = decoded.payload.accounts.map(
|
|
257
|
+
(account: { address: string; publicKey: string; label?: string }) =>
|
|
258
|
+
new ReadonlyWalletAccount({
|
|
259
|
+
address: account.address,
|
|
260
|
+
publicKey: account.publicKey ? fromBase64(account.publicKey) : new Uint8Array(0),
|
|
261
|
+
chains: [...SUI_CHAINS],
|
|
262
|
+
features: [...WALLET_FEATURES],
|
|
263
|
+
label: account.label,
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
this.#events.emit('change', { accounts: this.#accounts });
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
#tryRestoreSession(): void {
|
|
270
|
+
if (typeof localStorage === 'undefined') return;
|
|
271
|
+
const session = localStorage.getItem(this.#sessionKey);
|
|
272
|
+
if (!session) return;
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
this.#setAccountsFromSession(session);
|
|
276
|
+
} catch {
|
|
277
|
+
this.#clearSession();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
export { DevWalletClient, devWalletClientInitializer } from './dev-wallet-client.js';
|
|
5
|
+
export type { DevWalletClientOptions } from './dev-wallet-client.js';
|
|
6
|
+
export { parseWalletRequest } from './request-handler.js';
|
|
7
|
+
export type { PendingWalletRequest, HandleRequestOptions } from './request-handler.js';
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { ClientWithCoreApi } from '@mysten/sui/client';
|
|
5
|
+
import { fromBase64, toBase64 } from '@mysten/sui/utils';
|
|
6
|
+
import { createJwtSession, WalletPostMessageChannel } from '@mysten/window-wallet-core';
|
|
7
|
+
|
|
8
|
+
import type { SignerAdapter } from '../types.js';
|
|
9
|
+
import { getNetworkFromChain } from '../wallet/constants.js';
|
|
10
|
+
import { executeSigning } from '../wallet/signing.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A parsed wallet request with methods to approve or reject it.
|
|
14
|
+
*
|
|
15
|
+
* This is different from `PendingSigningRequest` (in dev-wallet.ts) — this interface
|
|
16
|
+
* includes `approve()`/`reject()` methods and is specific to the standalone popup flow.
|
|
17
|
+
*/
|
|
18
|
+
export interface PendingWalletRequest {
|
|
19
|
+
type: 'connect' | 'sign-transaction' | 'sign-and-execute-transaction' | 'sign-personal-message';
|
|
20
|
+
appName: string;
|
|
21
|
+
appUrl: string;
|
|
22
|
+
address?: string;
|
|
23
|
+
chain?: string;
|
|
24
|
+
data?: string | Uint8Array;
|
|
25
|
+
/**
|
|
26
|
+
* Approve the request.
|
|
27
|
+
* For connect: creates a session with the selected accounts (or all if none specified).
|
|
28
|
+
* For signing: signs with the adapter.
|
|
29
|
+
*/
|
|
30
|
+
approve(options?: { selectedAddresses?: string[] }): Promise<void>;
|
|
31
|
+
/** Reject the request with an optional reason. */
|
|
32
|
+
reject(reason?: string): void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface HandleRequestOptions {
|
|
36
|
+
/** The signer adapters providing accounts and signing capability. */
|
|
37
|
+
adapters: SignerAdapter[];
|
|
38
|
+
/** JWT secret key for session creation. */
|
|
39
|
+
jwtSecretKey: CryptoKey | Uint8Array;
|
|
40
|
+
/** Resolve a client for a given network name (needed for signAndExecute). */
|
|
41
|
+
getClient?: (network: string) => ClientWithCoreApi | undefined;
|
|
42
|
+
/** URL hash containing the encoded request. Defaults to window.location.hash. */
|
|
43
|
+
hash?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function parseWalletRequest(options: HandleRequestOptions): PendingWalletRequest {
|
|
47
|
+
if (!options.hash && typeof window === 'undefined') {
|
|
48
|
+
throw new Error(
|
|
49
|
+
'parseWalletRequest requires either options.hash or a browser environment with window.location',
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const hash = options.hash ?? window.location.hash.slice(1);
|
|
53
|
+
const channel = WalletPostMessageChannel.fromUrlHash(hash);
|
|
54
|
+
const requestData = channel.getRequestData();
|
|
55
|
+
const payload = requestData.payload;
|
|
56
|
+
|
|
57
|
+
if (payload.type === 'connect') {
|
|
58
|
+
return {
|
|
59
|
+
type: 'connect',
|
|
60
|
+
appName: requestData.appName,
|
|
61
|
+
appUrl: requestData.appUrl,
|
|
62
|
+
async approve(approveOptions?: { selectedAddresses?: string[] }) {
|
|
63
|
+
const allAccounts = options.adapters.flatMap((adapter) =>
|
|
64
|
+
adapter.getAccounts().map((a) => ({
|
|
65
|
+
address: a.address,
|
|
66
|
+
publicKey: toBase64(a.signer.getPublicKey().toSuiBytes()),
|
|
67
|
+
label: a.label,
|
|
68
|
+
})),
|
|
69
|
+
);
|
|
70
|
+
const selected = approveOptions?.selectedAddresses;
|
|
71
|
+
const accounts = selected
|
|
72
|
+
? allAccounts.filter((a) => selected.includes(a.address))
|
|
73
|
+
: allAccounts;
|
|
74
|
+
|
|
75
|
+
const session = await createJwtSession(
|
|
76
|
+
{ accounts },
|
|
77
|
+
{
|
|
78
|
+
secretKey: options.jwtSecretKey,
|
|
79
|
+
expirationTime: '7d',
|
|
80
|
+
issuer: 'dev-wallet',
|
|
81
|
+
audience: new URL(requestData.appUrl).origin,
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
channel.sendMessage({
|
|
86
|
+
type: 'resolve',
|
|
87
|
+
data: { type: 'connect', session },
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
reject(reason?: string) {
|
|
91
|
+
channel.sendMessage({ type: 'reject', reason });
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const messageData =
|
|
97
|
+
payload.type === 'sign-personal-message' ? fromBase64(payload.message) : payload.transaction;
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
type: payload.type,
|
|
101
|
+
appName: requestData.appName,
|
|
102
|
+
appUrl: requestData.appUrl,
|
|
103
|
+
address: payload.address,
|
|
104
|
+
chain: payload.chain,
|
|
105
|
+
data: messageData,
|
|
106
|
+
async approve() {
|
|
107
|
+
// Verify JWT session before signing — ensures the dApp was previously
|
|
108
|
+
// authorized for this account via a connect flow
|
|
109
|
+
try {
|
|
110
|
+
await channel.verifyJwtSession(options.jwtSecretKey);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
channel.sendMessage({
|
|
113
|
+
type: 'reject',
|
|
114
|
+
reason: `Session verification failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
115
|
+
});
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let account;
|
|
120
|
+
for (const adapter of options.adapters) {
|
|
121
|
+
account = adapter.getAccount(payload.address);
|
|
122
|
+
if (account) break;
|
|
123
|
+
}
|
|
124
|
+
if (!account) {
|
|
125
|
+
channel.sendMessage({
|
|
126
|
+
type: 'reject',
|
|
127
|
+
reason: `Account ${payload.address} not found`,
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const network = payload.chain ? getNetworkFromChain(payload.chain) : undefined;
|
|
134
|
+
const client = network ? options.getClient?.(network) : undefined;
|
|
135
|
+
const result = await executeSigning({
|
|
136
|
+
type: payload.type,
|
|
137
|
+
signer: account.signer,
|
|
138
|
+
data: messageData,
|
|
139
|
+
client,
|
|
140
|
+
});
|
|
141
|
+
// effects must be a string in the PostMessage protocol
|
|
142
|
+
const data =
|
|
143
|
+
result.type === 'sign-and-execute-transaction'
|
|
144
|
+
? { ...result, effects: result.effects ?? '' }
|
|
145
|
+
: result;
|
|
146
|
+
channel.sendMessage({
|
|
147
|
+
type: 'resolve',
|
|
148
|
+
data,
|
|
149
|
+
});
|
|
150
|
+
} catch (error) {
|
|
151
|
+
channel.sendMessage({
|
|
152
|
+
type: 'reject',
|
|
153
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
reject(reason?: string) {
|
|
158
|
+
channel.sendMessage({ type: 'reject', reason });
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
export { DevWallet, DEFAULT_NETWORK_URLS } from './wallet/dev-wallet.js';
|
|
5
|
+
export { devWalletInitializer } from './wallet/initializer.js';
|
|
6
|
+
export type { DevWalletInitializerConfig } from './wallet/initializer.js';
|
|
7
|
+
export type { SigningResult } from './wallet/signing.js';
|
|
8
|
+
export type {
|
|
9
|
+
AutoApprovePolicy,
|
|
10
|
+
DevWalletConfig,
|
|
11
|
+
PendingConnectRequest,
|
|
12
|
+
PendingSigningRequest,
|
|
13
|
+
} from './wallet/dev-wallet.js';
|
|
14
|
+
export type {
|
|
15
|
+
SignerAdapter,
|
|
16
|
+
ManagedAccount,
|
|
17
|
+
CreateAccountOptions,
|
|
18
|
+
ImportAccountOptions,
|
|
19
|
+
} from './types.js';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
if (typeof customElements === 'undefined') {
|
|
5
|
+
throw new Error(
|
|
6
|
+
'@mysten-incubation/dev-wallet/react components require a browser environment. ' +
|
|
7
|
+
'Use dynamic imports with ssr:false in Next.js.',
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
import { createComponent, type EventName } from '@lit/react';
|
|
12
|
+
import * as React from 'react';
|
|
13
|
+
|
|
14
|
+
import { DevWalletAccounts as DevWalletAccountsElement } from '../ui/dev-wallet-accounts.js';
|
|
15
|
+
import { DevWalletBalances as DevWalletBalancesElement } from '../ui/dev-wallet-balances.js';
|
|
16
|
+
import { DevWalletNewAccount as DevWalletNewAccountElement } from '../ui/dev-wallet-new-account.js';
|
|
17
|
+
import { DevWalletPanel as DevWalletPanelElement } from '../ui/dev-wallet-panel.js';
|
|
18
|
+
import { DevWalletSigning as DevWalletSigningElement } from '../ui/dev-wallet-signing.js';
|
|
19
|
+
|
|
20
|
+
export const DevWalletPanel = createComponent({
|
|
21
|
+
react: React,
|
|
22
|
+
tagName: 'dev-wallet-panel',
|
|
23
|
+
elementClass: DevWalletPanelElement,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export const DevWalletAccounts = createComponent({
|
|
27
|
+
react: React,
|
|
28
|
+
tagName: 'dev-wallet-accounts',
|
|
29
|
+
elementClass: DevWalletAccountsElement,
|
|
30
|
+
events: {
|
|
31
|
+
onAccountSelected: 'account-selected' as EventName<
|
|
32
|
+
CustomEvent<{ account: import('@mysten/wallet-standard').ReadonlyWalletAccount }>
|
|
33
|
+
>,
|
|
34
|
+
onAccountRenamed: 'account-renamed' as EventName<
|
|
35
|
+
CustomEvent<{ address: string; label: string }>
|
|
36
|
+
>,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const DevWalletBalances = createComponent({
|
|
41
|
+
react: React,
|
|
42
|
+
tagName: 'dev-wallet-balances',
|
|
43
|
+
elementClass: DevWalletBalancesElement,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export const DevWalletNewAccount = createComponent({
|
|
47
|
+
react: React,
|
|
48
|
+
tagName: 'dev-wallet-new-account',
|
|
49
|
+
elementClass: DevWalletNewAccountElement,
|
|
50
|
+
events: {
|
|
51
|
+
onClose: 'close' as EventName<CustomEvent>,
|
|
52
|
+
onAccountCreated: 'account-created' as EventName<CustomEvent>,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const DevWalletSigning = createComponent({
|
|
57
|
+
react: React,
|
|
58
|
+
tagName: 'dev-wallet-signing',
|
|
59
|
+
elementClass: DevWalletSigningElement,
|
|
60
|
+
events: {
|
|
61
|
+
onApprove: 'approve' as EventName<CustomEvent>,
|
|
62
|
+
onReject: 'reject' as EventName<CustomEvent>,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { createContext, createElement, useContext } from 'react';
|
|
5
|
+
import type { ReactNode } from 'react';
|
|
6
|
+
|
|
7
|
+
import type { DevWallet } from '../wallet/dev-wallet.js';
|
|
8
|
+
|
|
9
|
+
export const DevWalletContext = createContext<DevWallet | null>(null);
|
|
10
|
+
|
|
11
|
+
export interface DevWalletProviderProps {
|
|
12
|
+
wallet: DevWallet;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function DevWalletProvider({ wallet, children }: DevWalletProviderProps) {
|
|
17
|
+
return createElement(DevWalletContext.Provider, { value: wallet }, children);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param wallet - If provided, context is bypassed.
|
|
22
|
+
* @throws If no wallet is provided and no DevWalletProvider is in the tree.
|
|
23
|
+
*/
|
|
24
|
+
export function useDevWalletInstance(wallet?: DevWallet): DevWallet {
|
|
25
|
+
const contextValue = useContext(DevWalletContext);
|
|
26
|
+
|
|
27
|
+
if (wallet) {
|
|
28
|
+
return wallet;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!contextValue) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
'Could not find DevWalletContext. Ensure that you have set up the DevWalletProvider.',
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return contextValue;
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
export { useDevWallet } from './useDevWallet.js';
|
|
5
|
+
export type { UseDevWalletOptions, UseDevWalletResult } from './useDevWallet.js';
|
|
6
|
+
|
|
7
|
+
export { DevWalletContext, DevWalletProvider, useDevWalletInstance } from './context.js';
|
|
8
|
+
export type { DevWalletProviderProps } from './context.js';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
DevWalletAccounts,
|
|
12
|
+
DevWalletBalances,
|
|
13
|
+
DevWalletNewAccount,
|
|
14
|
+
DevWalletPanel,
|
|
15
|
+
DevWalletSigning,
|
|
16
|
+
} from './components.js';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import { mountDevWallet } from '../ui/mount.js';
|
|
7
|
+
import { DevWallet, type DevWalletConfig } from '../wallet/dev-wallet.js';
|
|
8
|
+
|
|
9
|
+
export interface UseDevWalletOptions extends DevWalletConfig {
|
|
10
|
+
/** Whether to call adapter.initialize() automatically. Defaults to true. */
|
|
11
|
+
autoInitialize?: boolean;
|
|
12
|
+
/** Whether to create an initial account after initialization (if adapter supports it). Defaults to true. */
|
|
13
|
+
createInitialAccount?: boolean;
|
|
14
|
+
/** Whether to mount the floating wallet drawer UI. Defaults to true. */
|
|
15
|
+
mountUI?: boolean;
|
|
16
|
+
/** Container element for the UI drawer. Defaults to document.body. */
|
|
17
|
+
container?: HTMLElement;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UseDevWalletResult {
|
|
21
|
+
wallet: DevWallet | null;
|
|
22
|
+
/** Initialization error, if any (e.g. IndexedDB quota exceeded, adapter failure). */
|
|
23
|
+
error: Error | null;
|
|
24
|
+
/** True while the wallet is being initialized. */
|
|
25
|
+
loading: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* React hook that initializes a DevWallet, registers it with the wallet-standard
|
|
30
|
+
* registry, and optionally mounts the wallet drawer UI.
|
|
31
|
+
*
|
|
32
|
+
* The adapters are captured on first render and used for the wallet's
|
|
33
|
+
* lifetime. Pass stable references (created outside the component or via useMemo).
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* const adapters = useMemo(() => [new InMemorySignerAdapter()], []);
|
|
38
|
+
*
|
|
39
|
+
* const wallet = useDevWallet({ adapters, networks: { devnet: 'https://fullnode.devnet.sui.io:443' } });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function useDevWallet(options: UseDevWalletOptions): UseDevWalletResult {
|
|
43
|
+
const [wallet, setWallet] = useState<DevWallet | null>(null);
|
|
44
|
+
const [error, setError] = useState<Error | null>(null);
|
|
45
|
+
const [loading, setLoading] = useState(true);
|
|
46
|
+
const optionsRef = useRef(options);
|
|
47
|
+
optionsRef.current = options;
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
const {
|
|
51
|
+
autoInitialize = true,
|
|
52
|
+
createInitialAccount = true,
|
|
53
|
+
mountUI = true,
|
|
54
|
+
container,
|
|
55
|
+
...walletConfig
|
|
56
|
+
} = optionsRef.current;
|
|
57
|
+
|
|
58
|
+
let cancelled = false;
|
|
59
|
+
let unregister: (() => void) | undefined;
|
|
60
|
+
let unmountUI: (() => void) | undefined;
|
|
61
|
+
|
|
62
|
+
let devWallet: DevWallet;
|
|
63
|
+
try {
|
|
64
|
+
devWallet = new DevWallet(walletConfig);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
67
|
+
setLoading(false);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function setup() {
|
|
72
|
+
if (autoInitialize) {
|
|
73
|
+
await Promise.all(walletConfig.adapters.map((a) => a.initialize()));
|
|
74
|
+
}
|
|
75
|
+
if (cancelled) return;
|
|
76
|
+
|
|
77
|
+
if (createInitialAccount) {
|
|
78
|
+
const hasAccounts = walletConfig.adapters.some((a) => a.getAccounts().length > 0);
|
|
79
|
+
if (!hasAccounts) {
|
|
80
|
+
const creatableAdapter = walletConfig.adapters.find(
|
|
81
|
+
(a) => a.createAccount && a.getAccounts().length === 0,
|
|
82
|
+
);
|
|
83
|
+
if (creatableAdapter?.createAccount) {
|
|
84
|
+
await creatableAdapter.createAccount({ label: 'Dev Account' });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (cancelled) return;
|
|
89
|
+
|
|
90
|
+
unregister = devWallet.register();
|
|
91
|
+
|
|
92
|
+
if (mountUI && typeof document !== 'undefined') {
|
|
93
|
+
unmountUI = mountDevWallet(devWallet, { container });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!cancelled) {
|
|
97
|
+
setWallet(devWallet);
|
|
98
|
+
setLoading(false);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
setup().catch((err) => {
|
|
103
|
+
if (!cancelled) {
|
|
104
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
105
|
+
setLoading(false);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return () => {
|
|
110
|
+
cancelled = true;
|
|
111
|
+
unmountUI?.();
|
|
112
|
+
unregister?.();
|
|
113
|
+
devWallet.destroy();
|
|
114
|
+
};
|
|
115
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
116
|
+
|
|
117
|
+
return useMemo(() => ({ wallet, error, loading }), [wallet, error, loading]);
|
|
118
|
+
}
|