@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.
Files changed (213) hide show
  1. package/README.md +250 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.107.0/helpers/decorate.mjs +10 -0
  3. package/dist/adapters/base-adapter.d.mts +33 -0
  4. package/dist/adapters/base-adapter.d.mts.map +1 -0
  5. package/dist/adapters/base-adapter.mjs +77 -0
  6. package/dist/adapters/base-adapter.mjs.map +1 -0
  7. package/dist/adapters/browser.d.mts +8 -0
  8. package/dist/adapters/browser.mjs +8 -0
  9. package/dist/adapters/build-managed-account.d.mts +12 -0
  10. package/dist/adapters/build-managed-account.d.mts.map +1 -0
  11. package/dist/adapters/build-managed-account.mjs +30 -0
  12. package/dist/adapters/build-managed-account.mjs.map +1 -0
  13. package/dist/adapters/idb-store.mjs +73 -0
  14. package/dist/adapters/idb-store.mjs.map +1 -0
  15. package/dist/adapters/in-memory-adapter.d.mts +16 -0
  16. package/dist/adapters/in-memory-adapter.d.mts.map +1 -0
  17. package/dist/adapters/in-memory-adapter.mjs +44 -0
  18. package/dist/adapters/in-memory-adapter.mjs.map +1 -0
  19. package/dist/adapters/passkey-adapter.d.mts +31 -0
  20. package/dist/adapters/passkey-adapter.d.mts.map +1 -0
  21. package/dist/adapters/passkey-adapter.mjs +87 -0
  22. package/dist/adapters/passkey-adapter.mjs.map +1 -0
  23. package/dist/adapters/remote-cli-adapter.d.mts +65 -0
  24. package/dist/adapters/remote-cli-adapter.d.mts.map +1 -0
  25. package/dist/adapters/remote-cli-adapter.mjs +299 -0
  26. package/dist/adapters/remote-cli-adapter.mjs.map +1 -0
  27. package/dist/adapters/webcrypto-adapter.d.mts +20 -0
  28. package/dist/adapters/webcrypto-adapter.d.mts.map +1 -0
  29. package/dist/adapters/webcrypto-adapter.mjs +68 -0
  30. package/dist/adapters/webcrypto-adapter.mjs.map +1 -0
  31. package/dist/bin/cli.d.mts +1 -0
  32. package/dist/bin/cli.mjs +183 -0
  33. package/dist/bin/cli.mjs.map +1 -0
  34. package/dist/client/dev-wallet-client.d.mts +57 -0
  35. package/dist/client/dev-wallet-client.d.mts.map +1 -0
  36. package/dist/client/dev-wallet-client.mjs +223 -0
  37. package/dist/client/dev-wallet-client.mjs.map +1 -0
  38. package/dist/client/index.d.mts +3 -0
  39. package/dist/client/index.mjs +4 -0
  40. package/dist/client/request-handler.d.mts +42 -0
  41. package/dist/client/request-handler.d.mts.map +1 -0
  42. package/dist/client/request-handler.mjs +115 -0
  43. package/dist/client/request-handler.mjs.map +1 -0
  44. package/dist/index.d.mts +5 -0
  45. package/dist/index.mjs +4 -0
  46. package/dist/react/components.d.mts +32 -0
  47. package/dist/react/components.d.mts.map +1 -0
  48. package/dist/react/components.mjs +53 -0
  49. package/dist/react/components.mjs.map +1 -0
  50. package/dist/react/context.d.mts +22 -0
  51. package/dist/react/context.d.mts.map +1 -0
  52. package/dist/react/context.mjs +25 -0
  53. package/dist/react/context.mjs.map +1 -0
  54. package/dist/react/index.d.mts +4 -0
  55. package/dist/react/index.mjs +5 -0
  56. package/dist/react/useDevWallet.d.mts +38 -0
  57. package/dist/react/useDevWallet.d.mts.map +1 -0
  58. package/dist/react/useDevWallet.mjs +89 -0
  59. package/dist/react/useDevWallet.mjs.map +1 -0
  60. package/dist/server/cli-signing-middleware.d.mts +22 -0
  61. package/dist/server/cli-signing-middleware.d.mts.map +1 -0
  62. package/dist/server/cli-signing-middleware.mjs +117 -0
  63. package/dist/server/cli-signing-middleware.mjs.map +1 -0
  64. package/dist/server/index.d.mts +2 -0
  65. package/dist/server/index.mjs +3 -0
  66. package/dist/standalone/assets/in-memory-adapter-CBF4h2KD.js +1 -0
  67. package/dist/standalone/assets/main-VE4olb-Q.js +2841 -0
  68. package/dist/standalone/assets/webcrypto-adapter-DysAubFb.js +1 -0
  69. package/dist/standalone/bookmarklet.js +5 -0
  70. package/dist/standalone/index.html +48 -0
  71. package/dist/types.d.mts +55 -0
  72. package/dist/types.d.mts.map +1 -0
  73. package/dist/ui/copy-controller.mjs +43 -0
  74. package/dist/ui/copy-controller.mjs.map +1 -0
  75. package/dist/ui/dev-wallet-account-selector.d.mts +24 -0
  76. package/dist/ui/dev-wallet-account-selector.d.mts.map +1 -0
  77. package/dist/ui/dev-wallet-account-selector.mjs +268 -0
  78. package/dist/ui/dev-wallet-account-selector.mjs.map +1 -0
  79. package/dist/ui/dev-wallet-accounts.d.mts +29 -0
  80. package/dist/ui/dev-wallet-accounts.d.mts.map +1 -0
  81. package/dist/ui/dev-wallet-accounts.mjs +524 -0
  82. package/dist/ui/dev-wallet-accounts.mjs.map +1 -0
  83. package/dist/ui/dev-wallet-balances.d.mts +26 -0
  84. package/dist/ui/dev-wallet-balances.d.mts.map +1 -0
  85. package/dist/ui/dev-wallet-balances.mjs +130 -0
  86. package/dist/ui/dev-wallet-balances.mjs.map +1 -0
  87. package/dist/ui/dev-wallet-connect.d.mts +31 -0
  88. package/dist/ui/dev-wallet-connect.d.mts.map +1 -0
  89. package/dist/ui/dev-wallet-connect.mjs +225 -0
  90. package/dist/ui/dev-wallet-connect.mjs.map +1 -0
  91. package/dist/ui/dev-wallet-dropdown.d.mts +27 -0
  92. package/dist/ui/dev-wallet-dropdown.d.mts.map +1 -0
  93. package/dist/ui/dev-wallet-dropdown.mjs +121 -0
  94. package/dist/ui/dev-wallet-dropdown.mjs.map +1 -0
  95. package/dist/ui/dev-wallet-network-badge.d.mts +21 -0
  96. package/dist/ui/dev-wallet-network-badge.d.mts.map +1 -0
  97. package/dist/ui/dev-wallet-network-badge.mjs +121 -0
  98. package/dist/ui/dev-wallet-network-badge.mjs.map +1 -0
  99. package/dist/ui/dev-wallet-new-account.d.mts +31 -0
  100. package/dist/ui/dev-wallet-new-account.d.mts.map +1 -0
  101. package/dist/ui/dev-wallet-new-account.mjs +577 -0
  102. package/dist/ui/dev-wallet-new-account.mjs.map +1 -0
  103. package/dist/ui/dev-wallet-objects.d.mts +26 -0
  104. package/dist/ui/dev-wallet-objects.d.mts.map +1 -0
  105. package/dist/ui/dev-wallet-objects.mjs +276 -0
  106. package/dist/ui/dev-wallet-objects.mjs.map +1 -0
  107. package/dist/ui/dev-wallet-panel.d.mts +22 -0
  108. package/dist/ui/dev-wallet-panel.d.mts.map +1 -0
  109. package/dist/ui/dev-wallet-panel.mjs +192 -0
  110. package/dist/ui/dev-wallet-panel.mjs.map +1 -0
  111. package/dist/ui/dev-wallet-popup.d.mts +36 -0
  112. package/dist/ui/dev-wallet-popup.d.mts.map +1 -0
  113. package/dist/ui/dev-wallet-popup.mjs +137 -0
  114. package/dist/ui/dev-wallet-popup.mjs.map +1 -0
  115. package/dist/ui/dev-wallet-settings.d.mts +33 -0
  116. package/dist/ui/dev-wallet-settings.d.mts.map +1 -0
  117. package/dist/ui/dev-wallet-settings.mjs +635 -0
  118. package/dist/ui/dev-wallet-settings.mjs.map +1 -0
  119. package/dist/ui/dev-wallet-signing-modal.d.mts +32 -0
  120. package/dist/ui/dev-wallet-signing-modal.d.mts.map +1 -0
  121. package/dist/ui/dev-wallet-signing-modal.mjs +115 -0
  122. package/dist/ui/dev-wallet-signing-modal.mjs.map +1 -0
  123. package/dist/ui/dev-wallet-signing.d.mts +25 -0
  124. package/dist/ui/dev-wallet-signing.d.mts.map +1 -0
  125. package/dist/ui/dev-wallet-signing.mjs +544 -0
  126. package/dist/ui/dev-wallet-signing.mjs.map +1 -0
  127. package/dist/ui/dev-wallet-standalone.d.mts +23 -0
  128. package/dist/ui/dev-wallet-standalone.d.mts.map +1 -0
  129. package/dist/ui/dev-wallet-standalone.mjs +129 -0
  130. package/dist/ui/dev-wallet-standalone.mjs.map +1 -0
  131. package/dist/ui/dev-wallet-tab-bar.d.mts +19 -0
  132. package/dist/ui/dev-wallet-tab-bar.d.mts.map +1 -0
  133. package/dist/ui/dev-wallet-tab-bar.mjs +143 -0
  134. package/dist/ui/dev-wallet-tab-bar.mjs.map +1 -0
  135. package/dist/ui/index.d.mts +17 -0
  136. package/dist/ui/index.mjs +18 -0
  137. package/dist/ui/mount.d.mts +11 -0
  138. package/dist/ui/mount.d.mts.map +1 -0
  139. package/dist/ui/mount.mjs +17 -0
  140. package/dist/ui/mount.mjs.map +1 -0
  141. package/dist/ui/styles.mjs +250 -0
  142. package/dist/ui/styles.mjs.map +1 -0
  143. package/dist/ui/transaction-analyzer.mjs +58 -0
  144. package/dist/ui/transaction-analyzer.mjs.map +1 -0
  145. package/dist/ui/utils.mjs +98 -0
  146. package/dist/ui/utils.mjs.map +1 -0
  147. package/dist/ui/wallet-controller.mjs +275 -0
  148. package/dist/ui/wallet-controller.mjs.map +1 -0
  149. package/dist/wallet/constants.mjs +11 -0
  150. package/dist/wallet/constants.mjs.map +1 -0
  151. package/dist/wallet/dev-wallet.d.mts +118 -0
  152. package/dist/wallet/dev-wallet.d.mts.map +1 -0
  153. package/dist/wallet/dev-wallet.mjs +424 -0
  154. package/dist/wallet/dev-wallet.mjs.map +1 -0
  155. package/dist/wallet/initializer.d.mts +63 -0
  156. package/dist/wallet/initializer.d.mts.map +1 -0
  157. package/dist/wallet/initializer.mjs +75 -0
  158. package/dist/wallet/initializer.mjs.map +1 -0
  159. package/dist/wallet/signing.d.mts +35 -0
  160. package/dist/wallet/signing.d.mts.map +1 -0
  161. package/dist/wallet/signing.mjs +69 -0
  162. package/dist/wallet/signing.mjs.map +1 -0
  163. package/package.json +124 -0
  164. package/src/adapters/base-adapter.ts +93 -0
  165. package/src/adapters/browser.ts +15 -0
  166. package/src/adapters/build-managed-account.ts +33 -0
  167. package/src/adapters/idb-store.ts +87 -0
  168. package/src/adapters/in-memory-adapter.ts +51 -0
  169. package/src/adapters/passkey-adapter.ts +120 -0
  170. package/src/adapters/remote-cli-adapter.ts +388 -0
  171. package/src/adapters/webcrypto-adapter.ts +96 -0
  172. package/src/app/bookmarklet-entry.ts +77 -0
  173. package/src/app/index.html +48 -0
  174. package/src/app/main.ts +245 -0
  175. package/src/app/tsconfig.json +3 -0
  176. package/src/bin/cli.ts +214 -0
  177. package/src/client/dev-wallet-client.ts +280 -0
  178. package/src/client/index.ts +7 -0
  179. package/src/client/request-handler.ts +161 -0
  180. package/src/index.ts +19 -0
  181. package/src/react/components.ts +64 -0
  182. package/src/react/context.ts +38 -0
  183. package/src/react/index.ts +16 -0
  184. package/src/react/useDevWallet.ts +118 -0
  185. package/src/server/cli-signing-middleware.ts +146 -0
  186. package/src/server/index.ts +8 -0
  187. package/src/types.ts +58 -0
  188. package/src/ui/copy-controller.ts +49 -0
  189. package/src/ui/dev-wallet-account-selector.ts +283 -0
  190. package/src/ui/dev-wallet-accounts.ts +578 -0
  191. package/src/ui/dev-wallet-balances.ts +171 -0
  192. package/src/ui/dev-wallet-connect.ts +259 -0
  193. package/src/ui/dev-wallet-dropdown.ts +138 -0
  194. package/src/ui/dev-wallet-network-badge.ts +128 -0
  195. package/src/ui/dev-wallet-new-account.ts +662 -0
  196. package/src/ui/dev-wallet-objects.ts +336 -0
  197. package/src/ui/dev-wallet-panel.ts +207 -0
  198. package/src/ui/dev-wallet-popup.ts +169 -0
  199. package/src/ui/dev-wallet-settings.ts +692 -0
  200. package/src/ui/dev-wallet-signing-modal.ts +137 -0
  201. package/src/ui/dev-wallet-signing.ts +624 -0
  202. package/src/ui/dev-wallet-standalone.ts +136 -0
  203. package/src/ui/dev-wallet-tab-bar.ts +151 -0
  204. package/src/ui/index.ts +26 -0
  205. package/src/ui/mount.ts +21 -0
  206. package/src/ui/styles.ts +252 -0
  207. package/src/ui/transaction-analyzer.ts +60 -0
  208. package/src/ui/utils.ts +118 -0
  209. package/src/ui/wallet-controller.ts +340 -0
  210. package/src/wallet/constants.ts +17 -0
  211. package/src/wallet/dev-wallet.ts +597 -0
  212. package/src/wallet/initializer.ts +124 -0
  213. package/src/wallet/signing.ts +85 -0
@@ -0,0 +1,118 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { normalizeStructTag, parseStructTag } from '@mysten/sui/utils';
5
+
6
+ const NORMALIZED_SUI_COIN_TYPE =
7
+ '0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI';
8
+
9
+ const NORMALIZED_COIN_PREFIX =
10
+ '0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<';
11
+
12
+ export function isSuiCoinType(coinType: string): boolean {
13
+ try {
14
+ return normalizeStructTag(coinType) === NORMALIZED_SUI_COIN_TYPE;
15
+ } catch {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ export function formatAddress(address: string): string {
21
+ if (address.length <= 16) return address;
22
+ return `${address.slice(0, 8)}...${address.slice(-6)}`;
23
+ }
24
+
25
+ export function getCoinSymbol(coinType: string): string {
26
+ try {
27
+ const tag = parseStructTag(coinType);
28
+ return tag.name;
29
+ } catch {
30
+ return coinType;
31
+ }
32
+ }
33
+
34
+ /** Check if a type string is a Coin wrapper (0x2::coin::Coin<...>) */
35
+ export function isCoinType(type: string): boolean {
36
+ try {
37
+ return normalizeStructTag(type).startsWith(NORMALIZED_COIN_PREFIX);
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+
43
+ /** Extract the short struct name from a full Move type string */
44
+ export function getTypeName(type: string): string {
45
+ try {
46
+ return parseStructTag(type).name;
47
+ } catch {
48
+ return type;
49
+ }
50
+ }
51
+
52
+ export async function copyToClipboard(text: string): Promise<boolean> {
53
+ try {
54
+ await navigator.clipboard.writeText(text);
55
+ return true;
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ export const NETWORK_COLORS: Record<string, string> = {
62
+ mainnet: '#f97316',
63
+ testnet: '#22c55e',
64
+ devnet: '#3b82f6',
65
+ localnet: '#6b7280',
66
+ };
67
+
68
+ export interface PairableAdapter {
69
+ readonly isPaired: boolean;
70
+ }
71
+
72
+ export function isPairableAdapter(adapter: unknown): adapter is PairableAdapter {
73
+ return adapter != null && typeof adapter === 'object' && 'isPaired' in adapter;
74
+ }
75
+
76
+ /** Dispatch a composed, bubbling custom event from a host element. */
77
+ export function emitEvent(host: HTMLElement, name: string, detail?: unknown): void {
78
+ host.dispatchEvent(new CustomEvent(name, { bubbles: true, composed: true, detail }));
79
+ }
80
+
81
+ /** Clone a Set and toggle an item in/out of it. */
82
+ export function toggleSetItem<T>(set: Set<T>, item: T): Set<T> {
83
+ const next = new Set(set);
84
+ if (next.has(item)) {
85
+ next.delete(item);
86
+ } else {
87
+ next.add(item);
88
+ }
89
+ return next;
90
+ }
91
+
92
+ /** Extract a user-facing error message, with a fallback for non-Error throws. */
93
+ export function getErrorMessage(error: unknown, fallback: string): string {
94
+ return error instanceof Error ? error.message : fallback;
95
+ }
96
+
97
+ export { getNetworkFromChain } from '../wallet/constants.js';
98
+
99
+ /** Find the adapter that owns a given address. */
100
+ export function findAdapterForAddress<T extends { getAccount(address: string): unknown }>(
101
+ adapters: readonly T[],
102
+ address: string,
103
+ ): T | undefined {
104
+ return adapters.find((a) => a.getAccount(address) !== undefined);
105
+ }
106
+
107
+ export function formatCoinBalance(balance: string | bigint, decimals: number): string {
108
+ if (decimals === 0) return balance.toString();
109
+
110
+ const value = typeof balance === 'string' ? BigInt(balance) : balance;
111
+ const divisor = BigInt(10 ** decimals);
112
+ const whole = value / divisor;
113
+ const fraction = value % divisor;
114
+
115
+ if (fraction === 0n) return whole.toString();
116
+ const fractionStr = fraction.toString().padStart(decimals, '0').replace(/0+$/, '');
117
+ return `${whole}.${fractionStr}`;
118
+ }
@@ -0,0 +1,340 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { ClientWithCoreApi } from '@mysten/sui/client';
5
+ import type { ReadonlyWalletAccount } from '@mysten/wallet-standard';
6
+ import { html, nothing } from 'lit';
7
+ import type { ReactiveController, ReactiveControllerHost } from 'lit';
8
+
9
+ import { getNetworkFromChain } from '../wallet/constants.js';
10
+ import type {
11
+ DevWallet,
12
+ PendingConnectRequest,
13
+ PendingSigningRequest,
14
+ } from '../wallet/dev-wallet.js';
15
+ import './dev-wallet-account-selector.js';
16
+ import './dev-wallet-balances.js';
17
+ import './dev-wallet-connect.js';
18
+ import './dev-wallet-network-badge.js';
19
+ import './dev-wallet-objects.js';
20
+ import './dev-wallet-settings.js';
21
+ import './dev-wallet-signing-modal.js';
22
+ import type { TabId } from './dev-wallet-tab-bar.js';
23
+ import './dev-wallet-tab-bar.js';
24
+
25
+ /**
26
+ * Lit Reactive Controller that encapsulates all shared wallet management logic
27
+ * between `dev-wallet-panel` and `dev-wallet-standalone`.
28
+ *
29
+ * Both components delegate state management, event subscription, and shared
30
+ * render fragments to this controller, keeping only layout-specific code.
31
+ */
32
+ export class WalletController implements ReactiveController {
33
+ host: ReactiveControllerHost;
34
+
35
+ activeTab: TabId = 'assets';
36
+ accounts: ReadonlyWalletAccount[] = [];
37
+ activeAccountIndex = 0;
38
+ pendingRequest: PendingSigningRequest | null = null;
39
+ pendingConnect: PendingConnectRequest | null = null;
40
+ bookmarkletOrigin = '';
41
+
42
+ #wallet: DevWallet | null = null;
43
+ #unsubscribeEvents: (() => void) | null = null;
44
+ #unsubscribeRequests: (() => void) | null = null;
45
+ #unsubscribeConnect: (() => void) | null = null;
46
+
47
+ constructor(host: ReactiveControllerHost) {
48
+ this.host = host;
49
+ host.addController(this);
50
+ }
51
+
52
+ get wallet(): DevWallet | null {
53
+ return this.#wallet;
54
+ }
55
+
56
+ get activeAddress(): string {
57
+ return this.accounts[this.activeAccountIndex]?.address ?? '';
58
+ }
59
+
60
+ set wallet(value: DevWallet | null) {
61
+ if (value === this.#wallet) return;
62
+ this.#unsubscribe();
63
+ this.#wallet = value;
64
+ this.#subscribe();
65
+ this.syncState();
66
+ }
67
+
68
+ hostConnected(): void {
69
+ this.#subscribe();
70
+ this.syncState();
71
+ }
72
+
73
+ hostDisconnected(): void {
74
+ this.#unsubscribe();
75
+ }
76
+
77
+ // ── State sync ──────────────────────────────────────────────────────────
78
+
79
+ syncState(): void {
80
+ if (!this.#wallet) return;
81
+ const newAccounts = this.#wallet.accounts;
82
+ const newPending = this.#wallet.pendingRequest;
83
+
84
+ const accountsChanged =
85
+ newAccounts.length !== this.accounts.length ||
86
+ newAccounts.some((a, i) => a.address !== this.accounts[i]?.address);
87
+ const pendingChanged = newPending !== this.pendingRequest;
88
+
89
+ if (!accountsChanged && !pendingChanged) return;
90
+
91
+ if (accountsChanged) {
92
+ this.accounts = [...newAccounts];
93
+ // Clamp activeAccountIndex when accounts shrink
94
+ if (this.activeAccountIndex >= newAccounts.length && newAccounts.length > 0) {
95
+ this.activeAccountIndex = newAccounts.length - 1;
96
+ }
97
+ }
98
+ this.pendingRequest = newPending;
99
+ this.host.requestUpdate();
100
+ }
101
+
102
+ syncConnectState(): void {
103
+ if (!this.#wallet) return;
104
+ const newConnect = this.#wallet.pendingConnect;
105
+ if (newConnect === this.pendingConnect) return;
106
+ this.pendingConnect = newConnect;
107
+ this.host.requestUpdate();
108
+ }
109
+
110
+ // ── Client resolution ───────────────────────────────────────────────────
111
+
112
+ getActiveClient(): ClientWithCoreApi | null {
113
+ if (!this.#wallet) return null;
114
+
115
+ if (this.pendingRequest) {
116
+ const network = getNetworkFromChain(this.pendingRequest.chain);
117
+ if (network) {
118
+ try {
119
+ return this.#wallet.getClient(network);
120
+ } catch {
121
+ return this.#wallet.activeClient;
122
+ }
123
+ }
124
+ }
125
+
126
+ return this.#wallet.activeClient;
127
+ }
128
+
129
+ // ── Event handlers ──────────────────────────────────────────────────────
130
+
131
+ async handleApprove(): Promise<void> {
132
+ if (!this.#wallet) return;
133
+ try {
134
+ await this.#wallet.approveRequest();
135
+ } catch (error) {
136
+ console.error('[dev-wallet] approve failed:', error);
137
+ }
138
+ }
139
+
140
+ handleReject(): void {
141
+ if (!this.#wallet) return;
142
+ try {
143
+ this.#wallet.rejectRequest();
144
+ } catch (error) {
145
+ console.error('[dev-wallet] reject failed:', error);
146
+ }
147
+ }
148
+
149
+ handleTabChanged(e: CustomEvent<{ tab: TabId }>): void {
150
+ this.activeTab = e.detail.tab;
151
+ this.host.requestUpdate();
152
+ }
153
+
154
+ handleNetworkChanged(e: CustomEvent<{ network: string }>): void {
155
+ this.#wallet?.setActiveNetwork(e.detail.network);
156
+ }
157
+
158
+ handleAccountSelected(e: CustomEvent<{ account: ReadonlyWalletAccount }>): void {
159
+ const index = this.accounts.findIndex((a) => a.address === e.detail.account.address);
160
+ if (index !== -1) {
161
+ this.activeAccountIndex = index;
162
+ this.host.requestUpdate();
163
+ }
164
+ }
165
+
166
+ handleApproveConnect(e: CustomEvent<{ selectedAddresses: string[] }>): void {
167
+ e.stopPropagation();
168
+ if (!this.#wallet) return;
169
+ try {
170
+ this.#wallet.approveConnect(e.detail.selectedAddresses);
171
+ } catch (error) {
172
+ console.error('[dev-wallet] connect approve failed:', error);
173
+ }
174
+ }
175
+
176
+ handleRejectConnect(e?: Event): void {
177
+ e?.preventDefault();
178
+ if (e instanceof CustomEvent) e.stopPropagation();
179
+ if (!this.#wallet) return;
180
+ try {
181
+ this.#wallet.rejectConnect();
182
+ } catch (error) {
183
+ console.error('[dev-wallet] connect reject failed:', error);
184
+ }
185
+ }
186
+
187
+ // ── Shared render fragments ─────────────────────────────────────────────
188
+
189
+ renderAccountSelector() {
190
+ return html`
191
+ <div class="section">
192
+ <dev-wallet-account-selector
193
+ exportparts="trigger: selector-trigger, copy-button: selector-copy-button, empty-state: selector-empty-state"
194
+ .accounts=${this.accounts}
195
+ .adapters=${this.#wallet ? [...this.#wallet.adapters] : []}
196
+ .activeAddress=${this.activeAddress}
197
+ @account-selected=${(e: CustomEvent) => this.handleAccountSelected(e)}
198
+ ></dev-wallet-account-selector>
199
+ </div>
200
+ `;
201
+ }
202
+
203
+ renderAssetsTab() {
204
+ return html`
205
+ ${this.renderAccountSelector()}
206
+ ${this.activeAddress && this.#wallet
207
+ ? html`
208
+ <div class="section">
209
+ <dev-wallet-balances
210
+ exportparts="balance-list, loading: balances-loading, error-message: balances-error-message, empty-state: balances-empty-state"
211
+ .address=${this.activeAddress}
212
+ .client=${this.getActiveClient()}
213
+ ></dev-wallet-balances>
214
+ </div>
215
+ `
216
+ : nothing}
217
+ `;
218
+ }
219
+
220
+ renderObjectsTab() {
221
+ return html`
222
+ ${this.renderAccountSelector()}
223
+ <dev-wallet-objects
224
+ exportparts="object-list, loading: objects-loading, error-message: objects-error-message, empty-state: objects-empty-state, load-more-button"
225
+ .address=${this.activeAddress}
226
+ .client=${this.getActiveClient()}
227
+ ></dev-wallet-objects>
228
+ `;
229
+ }
230
+
231
+ renderSettingsTab() {
232
+ return html`
233
+ <dev-wallet-settings
234
+ exportparts="accounts-account-list, accounts-add-button, accounts-empty-state"
235
+ .wallet=${this.#wallet}
236
+ .accounts=${this.accounts}
237
+ .adapters=${this.#wallet ? [...this.#wallet.adapters] : []}
238
+ .activeAddress=${this.activeAddress}
239
+ .bookmarkletOrigin=${this.bookmarkletOrigin}
240
+ @account-selected=${(e: CustomEvent) => this.handleAccountSelected(e)}
241
+ ></dev-wallet-settings>
242
+ `;
243
+ }
244
+
245
+ renderTabContent() {
246
+ if (this.activeTab === 'assets') return this.renderAssetsTab();
247
+ if (this.activeTab === 'objects') return this.renderObjectsTab();
248
+ if (this.activeTab === 'settings') return this.renderSettingsTab();
249
+ return nothing;
250
+ }
251
+
252
+ renderSigningModal() {
253
+ if (!this.pendingRequest) return nothing;
254
+
255
+ return html`
256
+ <dev-wallet-signing-modal
257
+ exportparts="signing-approve-button, signing-reject-button, signing-request-type, signing-empty-state, signing-error-message, signing-footer, dialog: signing-dialog"
258
+ .request=${this.pendingRequest}
259
+ .client=${this.getActiveClient()}
260
+ .walletName=${this.#wallet?.name ?? 'Dev Wallet'}
261
+ @approve=${() => this.handleApprove()}
262
+ @reject=${() => this.handleReject()}
263
+ ></dev-wallet-signing-modal>
264
+ `;
265
+ }
266
+
267
+ renderConnectPicker() {
268
+ if (!this.pendingConnect) return nothing;
269
+
270
+ const allAccounts = this.#wallet
271
+ ? this.#wallet.adapters.flatMap((a) =>
272
+ a.getAccounts().map((acc) => ({
273
+ address: acc.address,
274
+ label: acc.label,
275
+ adapterName: a.name,
276
+ })),
277
+ )
278
+ : [];
279
+
280
+ return html`
281
+ <dialog class="connect-dialog" @cancel=${(e: Event) => this.handleRejectConnect(e)}>
282
+ <div class="connect-dialog-header">
283
+ <span class="connect-dialog-title">${this.#wallet?.name ?? 'Dev Wallet'}</span>
284
+ </div>
285
+ <dev-wallet-connect
286
+ exportparts="approve-button: connect-approve-button, reject-button: connect-reject-button, account-list: connect-account-list, error-message: connect-error-message"
287
+ .accounts=${allAccounts}
288
+ @approve=${(e: CustomEvent) => this.handleApproveConnect(e)}
289
+ @reject=${(e: Event) => this.handleRejectConnect(e)}
290
+ ></dev-wallet-connect>
291
+ </dialog>
292
+ `;
293
+ }
294
+
295
+ renderNetworkBadge() {
296
+ if (!this.#wallet) return nothing;
297
+ return html`
298
+ <dev-wallet-network-badge
299
+ exportparts="trigger: network-trigger"
300
+ .active=${this.#wallet.activeNetwork}
301
+ .networks=${this.#wallet.availableNetworks}
302
+ @network-changed=${(e: CustomEvent) => this.handleNetworkChanged(e)}
303
+ ></dev-wallet-network-badge>
304
+ `;
305
+ }
306
+
307
+ renderTabBar() {
308
+ return html`
309
+ <dev-wallet-tab-bar
310
+ exportparts="tab-bar, tab"
311
+ .active=${this.activeTab}
312
+ @tab-changed=${(e: CustomEvent) => this.handleTabChanged(e)}
313
+ ></dev-wallet-tab-bar>
314
+ `;
315
+ }
316
+
317
+ // ── Subscriptions ───────────────────────────────────────────────────────
318
+
319
+ #subscribe(): void {
320
+ if (!this.#wallet) return;
321
+ this.#unsubscribeEvents = this.#wallet.features['standard:events'].on('change', () => {
322
+ this.syncState();
323
+ });
324
+ this.#unsubscribeRequests = this.#wallet.onRequestChange(() => {
325
+ this.syncState();
326
+ });
327
+ this.#unsubscribeConnect = this.#wallet.onConnectChange(() => {
328
+ this.syncConnectState();
329
+ });
330
+ }
331
+
332
+ #unsubscribe(): void {
333
+ this.#unsubscribeEvents?.();
334
+ this.#unsubscribeEvents = null;
335
+ this.#unsubscribeRequests?.();
336
+ this.#unsubscribeRequests = null;
337
+ this.#unsubscribeConnect?.();
338
+ this.#unsubscribeConnect = null;
339
+ }
340
+ }
@@ -0,0 +1,17 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { StandardEventsListeners, WalletIcon } from '@mysten/wallet-standard';
5
+
6
+ export type WalletEventsMap = {
7
+ [E in keyof StandardEventsListeners]: Parameters<StandardEventsListeners[E]>[0];
8
+ };
9
+
10
+ /** Extract the network name from a chain identifier (e.g. 'sui:devnet' → 'devnet'). */
11
+ export function getNetworkFromChain(chain: string): string | undefined {
12
+ return chain.split(':')[1];
13
+ }
14
+
15
+ /** Default wallet icon shared between DevWallet and DevWalletClient. */
16
+ export const DEFAULT_WALLET_ICON: WalletIcon =
17
+ 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCIgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0Ij4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0id2FsbGV0R3JhZCIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMTAwJSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0eWxlPSJzdG9wLWNvbG9yOiM2MzY2RjEiIC8+CiAgICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3R5bGU9InN0b3AtY29sb3I6IzI1NjNFQiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImZsYXBHcmFkIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIxMDAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3R5bGU9InN0b3AtY29sb3I6IzgxOENGOCIgLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdHlsZT0ic3RvcC1jb2xvcjojNEY0NkU1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPCEtLSBTaGFkb3cgLS0+CiAgPHJlY3QgeD0iOSIgeT0iMjEiIHdpZHRoPSI1MCIgaGVpZ2h0PSIzNiIgcng9IjYiIHJ5PSI2IiBmaWxsPSIjMDAwIiBvcGFjaXR5PSIwLjEiIC8+CiAgPCEtLSBXYWxsZXQgYm9keSAtLT4KICA8cmVjdCB4PSI2IiB5PSIxOCIgd2lkdGg9IjUwIiBoZWlnaHQ9IjM2IiByeD0iNiIgcnk9IjYiIGZpbGw9InVybCgjd2FsbGV0R3JhZCkiIC8+CiAgPCEtLSBGbGFwIC0tPgogIDxwYXRoIGQ9Ik02IDI2IEw2IDIyIEM2IDE1IDggMTIgMTQgMTIgTDQ2IDEyIEM1MiAxMiA1NiAxNSA1NiAyMiBMNTYgMjYgWiIgZmlsbD0idXJsKCNmbGFwR3JhZCkiIC8+CiAgPCEtLSBDbGFzcCAtLT4KICA8cmVjdCB4PSI0MiIgeT0iMzAiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxMiIgcng9IjQiIHJ5PSI0IiBmaWxsPSIjNDMzOENBIiAvPgogIDwhLS0gR29sZCBjb2luIGluIGNsYXNwIC0tPgogIDxjaXJjbGUgY3g9IjQ4IiBjeT0iMzYiIHI9IjMuNSIgZmlsbD0iI0ZDRDM0RCIgLz4KICA8Y2lyY2xlIGN4PSI0OCIgY3k9IjM2IiByPSIyIiBmaWxsPSIjRjU5RTBCIiAvPgogIDwhLS0gRW1ib3NzZWQgRFcgdGV4dCAtLT4KICA8dGV4dCB4PSIyNiIgeT0iNDUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmIiBmb250LXdlaWdodD0iOTAwIiBmb250LXNpemU9IjE4IiBmaWxsPSIjMzczMEEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkb21pbmFudC1iYXNlbGluZT0ibWlkZGxlIiBsZXR0ZXItc3BhY2luZz0iMiI+RFc8L3RleHQ+CiAgPHRleHQgeD0iMjYiIHk9IjQ0IiBmb250LWZhbWlseT0iQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZiIgZm9udC13ZWlnaHQ9IjkwMCIgZm9udC1zaXplPSIxOCIgZmlsbD0iI0M3RDJGRSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZG9taW5hbnQtYmFzZWxpbmU9Im1pZGxlIiBsZXR0ZXItc3BhY2luZz0iMiI+RFc8L3RleHQ+Cjwvc3ZnPgo=';