@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,336 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { ClientWithCoreApi } from '@mysten/sui/client';
5
+ import { css, html, LitElement, nothing } from 'lit';
6
+ import { customElement, property, state } from 'lit/decorators.js';
7
+
8
+ import { CopyController } from './copy-controller.js';
9
+ import { sectionHeaderStyles, sharedStyles, stateStyles } from './styles.js';
10
+ import { getTypeName, isCoinType } from './utils.js';
11
+
12
+ interface OwnedObject {
13
+ objectId: string;
14
+ type: string;
15
+ typeName: string;
16
+ version: string;
17
+ displayName: string | null;
18
+ description: string | null;
19
+ imageUrl: string | null;
20
+ }
21
+
22
+ @customElement('dev-wallet-objects')
23
+ export class DevWalletObjects extends LitElement {
24
+ static override styles = [
25
+ sharedStyles,
26
+ sectionHeaderStyles,
27
+ stateStyles,
28
+ css`
29
+ :host {
30
+ display: block;
31
+ }
32
+
33
+ .object-list {
34
+ display: flex;
35
+ flex-direction: column;
36
+ gap: 4px;
37
+ }
38
+
39
+ .object-item {
40
+ display: flex;
41
+ gap: 10px;
42
+ padding: 10px 12px;
43
+ border-radius: var(--dev-wallet-radius-sm);
44
+ border: 1px solid var(--dev-wallet-border);
45
+ background: var(--dev-wallet-secondary);
46
+ align-items: flex-start;
47
+ }
48
+
49
+ .object-thumb {
50
+ width: 40px;
51
+ height: 40px;
52
+ border-radius: var(--dev-wallet-radius-xs);
53
+ object-fit: cover;
54
+ flex-shrink: 0;
55
+ }
56
+
57
+ .object-body {
58
+ display: flex;
59
+ flex-direction: column;
60
+ gap: 2px;
61
+ flex: 1;
62
+ min-width: 0;
63
+ }
64
+
65
+ .object-top {
66
+ display: flex;
67
+ justify-content: space-between;
68
+ align-items: center;
69
+ }
70
+
71
+ .object-type {
72
+ font-size: 13px;
73
+ font-weight: var(--dev-wallet-font-weight-medium);
74
+ color: var(--dev-wallet-foreground);
75
+ white-space: nowrap;
76
+ overflow: hidden;
77
+ text-overflow: ellipsis;
78
+ }
79
+
80
+ .object-type-badge {
81
+ font-size: 10px;
82
+ color: var(--dev-wallet-muted-foreground);
83
+ opacity: 0.8;
84
+ }
85
+
86
+ .object-description {
87
+ font-size: 11px;
88
+ color: var(--dev-wallet-muted-foreground);
89
+ overflow: hidden;
90
+ text-overflow: ellipsis;
91
+ white-space: nowrap;
92
+ }
93
+
94
+ .object-version {
95
+ font-size: 11px;
96
+ color: var(--dev-wallet-muted-foreground);
97
+ flex-shrink: 0;
98
+ }
99
+
100
+ .object-id {
101
+ font-size: 11px;
102
+ font-family: var(--dev-wallet-font-mono);
103
+ color: var(--dev-wallet-muted-foreground);
104
+ cursor: pointer;
105
+ border-radius: var(--dev-wallet-radius-2xs);
106
+ padding: 1px 2px;
107
+ margin: -1px -2px;
108
+ transition: background 0.15s;
109
+ }
110
+
111
+ .object-id:hover {
112
+ background: color-mix(in oklab, var(--dev-wallet-primary) 15%, transparent);
113
+ }
114
+
115
+ .object-id.copied {
116
+ color: var(--dev-wallet-positive);
117
+ }
118
+
119
+ .load-more {
120
+ margin-top: 8px;
121
+ width: 100%;
122
+ padding: 8px;
123
+ border-radius: var(--dev-wallet-radius-sm);
124
+ font-size: 12px;
125
+ font-weight: var(--dev-wallet-font-weight-medium);
126
+ color: var(--dev-wallet-primary);
127
+ background: transparent;
128
+ border: 1px solid var(--dev-wallet-border);
129
+ transition: background 0.15s;
130
+ }
131
+
132
+ .load-more:hover {
133
+ background: var(--dev-wallet-secondary);
134
+ }
135
+
136
+ .load-more:disabled {
137
+ opacity: 0.5;
138
+ cursor: default;
139
+ }
140
+ `,
141
+ ];
142
+
143
+ @property({ type: String })
144
+ address = '';
145
+
146
+ @property({ attribute: false })
147
+ client: ClientWithCoreApi | null = null;
148
+
149
+ @state()
150
+ private _objects: OwnedObject[] = [];
151
+
152
+ @state()
153
+ private _loading = false;
154
+
155
+ @state()
156
+ private _loadingMore = false;
157
+
158
+ @state()
159
+ private _error: string | null = null;
160
+
161
+ @state()
162
+ private _hasNextPage = false;
163
+
164
+ #copy = new CopyController(this);
165
+ #cursor: string | null = null;
166
+ #lastFetchedAddress = '';
167
+ #lastFetchedClient: ClientWithCoreApi | null = null;
168
+ #fetchGeneration = 0;
169
+
170
+ override willUpdate(changedProperties: Map<string, unknown>) {
171
+ if (
172
+ (changedProperties.has('address') || changedProperties.has('client')) &&
173
+ this.address &&
174
+ this.client &&
175
+ (this.address !== this.#lastFetchedAddress || this.client !== this.#lastFetchedClient)
176
+ ) {
177
+ this.#fetchObjects(false);
178
+ }
179
+ }
180
+
181
+ override render() {
182
+ if (!this.address || !this.client) {
183
+ return nothing;
184
+ }
185
+
186
+ return html`
187
+ <h3 class="section-header">Objects</h3>
188
+ ${this._loading
189
+ ? html`<div class="loading" part="loading" aria-live="polite">Loading...</div>`
190
+ : this._error
191
+ ? html`<div class="error-state" part="error-message" aria-live="polite">
192
+ ${this._error}
193
+ </div>`
194
+ : this._objects.length === 0
195
+ ? html`<div class="empty-state" part="empty-state">No objects found</div>`
196
+ : html`
197
+ <div class="object-list" part="object-list">
198
+ ${this._objects.map(
199
+ (obj) => html`
200
+ <div class="object-item">
201
+ ${obj.imageUrl && /^https?:\/\//i.test(obj.imageUrl)
202
+ ? html`<img
203
+ class="object-thumb"
204
+ src=${obj.imageUrl}
205
+ alt=${obj.displayName ?? obj.typeName}
206
+ @error=${(e: Event) =>
207
+ ((e.target as HTMLImageElement).style.display = 'none')}
208
+ />`
209
+ : nothing}
210
+ <div class="object-body">
211
+ <div class="object-top">
212
+ <span class="object-type"> ${obj.displayName ?? obj.typeName} </span>
213
+ <span class="object-version">v${obj.version}</span>
214
+ </div>
215
+ ${obj.displayName
216
+ ? html`<span class="object-type-badge">${obj.typeName}</span>`
217
+ : nothing}
218
+ ${obj.description
219
+ ? html`<span class="object-description">${obj.description}</span>`
220
+ : nothing}
221
+ <span
222
+ class="object-id ${this.#copy.isCopied(obj.objectId) ? 'copied' : ''}"
223
+ title="Click to copy"
224
+ role="button"
225
+ tabindex="0"
226
+ aria-label="Copy object ID"
227
+ @click=${() => this.#copy.copy(obj.objectId)}
228
+ @keydown=${(e: KeyboardEvent) => {
229
+ if (e.key === 'Enter' || e.key === ' ') {
230
+ e.preventDefault();
231
+ this.#copy.copy(obj.objectId);
232
+ }
233
+ }}
234
+ >
235
+ ${this.#copy.isCopied(obj.objectId)
236
+ ? 'Copied!'
237
+ : `${obj.objectId.slice(0, 10)}...${obj.objectId.slice(-8)}`}
238
+ </span>
239
+ </div>
240
+ </div>
241
+ `,
242
+ )}
243
+ </div>
244
+ ${this._hasNextPage
245
+ ? html`
246
+ <button
247
+ class="load-more"
248
+ part="load-more-button"
249
+ ?disabled=${this._loadingMore}
250
+ @click=${this.#loadMore}
251
+ >
252
+ ${this._loadingMore ? 'Loading...' : 'Load More'}
253
+ </button>
254
+ `
255
+ : nothing}
256
+ `}
257
+ `;
258
+ }
259
+
260
+ async #fetchObjects(append: boolean) {
261
+ this.#lastFetchedAddress = this.address;
262
+ this.#lastFetchedClient = this.client;
263
+
264
+ if (!append) {
265
+ this.#cursor = null;
266
+ this._objects = [];
267
+ }
268
+
269
+ const generation = ++this.#fetchGeneration;
270
+ if (append) {
271
+ this._loadingMore = true;
272
+ } else {
273
+ this._loading = true;
274
+ }
275
+ this._error = null;
276
+
277
+ try {
278
+ const result = await this.client!.core.listOwnedObjects({
279
+ owner: this.address,
280
+ limit: 20,
281
+ cursor: this.#cursor,
282
+ include: { json: true },
283
+ });
284
+
285
+ if (generation !== this.#fetchGeneration) return;
286
+
287
+ // Filter out Coin types — those are shown in the balances tab
288
+ const nonCoinObjects: OwnedObject[] = result.objects
289
+ .filter((obj) => !isCoinType(obj.type))
290
+ .map((obj) => {
291
+ const json = obj.json;
292
+ return {
293
+ objectId: obj.objectId,
294
+ type: obj.type,
295
+ typeName: getTypeName(obj.type),
296
+ version: obj.version,
297
+ displayName: extractString(json, 'name'),
298
+ description: extractString(json, 'description'),
299
+ imageUrl: extractString(json, 'image_url') ?? extractString(json, 'img_url'),
300
+ };
301
+ });
302
+
303
+ this._objects = append ? [...this._objects, ...nonCoinObjects] : nonCoinObjects;
304
+ this._hasNextPage = result.hasNextPage;
305
+ this.#cursor = result.cursor;
306
+ } catch {
307
+ if (generation !== this.#fetchGeneration) return;
308
+ this._error = 'Failed to load objects';
309
+ if (!append) this._objects = [];
310
+ } finally {
311
+ if (generation === this.#fetchGeneration) {
312
+ this._loading = false;
313
+ this._loadingMore = false;
314
+ }
315
+ }
316
+ }
317
+
318
+ #loadMore() {
319
+ this.#fetchObjects(true);
320
+ }
321
+ }
322
+
323
+ function extractString(
324
+ json: Record<string, unknown> | null | undefined,
325
+ key: string,
326
+ ): string | null {
327
+ if (!json) return null;
328
+ const val = json[key];
329
+ return typeof val === 'string' && val.length > 0 ? val : null;
330
+ }
331
+
332
+ declare global {
333
+ interface HTMLElementTagNameMap {
334
+ 'dev-wallet-objects': DevWalletObjects;
335
+ }
336
+ }
@@ -0,0 +1,207 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { css, html, LitElement, nothing } from 'lit';
5
+ import { customElement, property, state } from 'lit/decorators.js';
6
+
7
+ import type { DevWallet } from '../wallet/dev-wallet.js';
8
+ import { connectDialogStyles, sharedStyles } from './styles.js';
9
+ import { WalletController } from './wallet-controller.js';
10
+
11
+ @customElement('dev-wallet-panel')
12
+ export class DevWalletPanel extends LitElement {
13
+ static override styles = [
14
+ sharedStyles,
15
+ connectDialogStyles,
16
+ css`
17
+ :host {
18
+ display: block;
19
+ position: fixed;
20
+ bottom: 16px;
21
+ right: 16px;
22
+ z-index: 999999;
23
+ font-size: 14px;
24
+ }
25
+
26
+ .trigger {
27
+ width: 48px;
28
+ height: 48px;
29
+ border-radius: 50%;
30
+ background: var(--dev-wallet-primary);
31
+ color: var(--dev-wallet-primary-foreground);
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ box-shadow: var(--dev-wallet-shadow-md);
36
+ transition: transform 0.15s;
37
+ position: relative;
38
+ }
39
+
40
+ .trigger:hover {
41
+ transform: scale(1.05);
42
+ }
43
+
44
+ .trigger svg {
45
+ width: 24px;
46
+ height: 24px;
47
+ }
48
+
49
+ .sidebar {
50
+ position: absolute;
51
+ bottom: 56px;
52
+ right: 0;
53
+ width: 360px;
54
+ max-width: calc(100vw - 32px);
55
+ max-height: 520px;
56
+ border-radius: var(--dev-wallet-radius-xl);
57
+ background: var(--dev-wallet-background);
58
+ border: 1px solid var(--dev-wallet-border);
59
+ box-shadow: var(--dev-wallet-shadow-lg);
60
+ display: flex;
61
+ flex-direction: column;
62
+ }
63
+
64
+ .sidebar-header {
65
+ display: flex;
66
+ justify-content: space-between;
67
+ align-items: center;
68
+ padding: 14px 16px;
69
+ border-bottom: 1px solid var(--dev-wallet-border);
70
+ position: relative;
71
+ z-index: 1;
72
+ }
73
+
74
+ .sidebar-title {
75
+ font-size: 15px;
76
+ font-weight: var(--dev-wallet-font-weight-semibold);
77
+ color: var(--dev-wallet-foreground);
78
+ }
79
+
80
+ .close-btn {
81
+ font-size: 18px;
82
+ color: var(--dev-wallet-muted-foreground);
83
+ width: 28px;
84
+ height: 28px;
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ border-radius: var(--dev-wallet-radius-xs);
89
+ }
90
+
91
+ .close-btn:hover {
92
+ background: var(--dev-wallet-secondary);
93
+ }
94
+
95
+ .sidebar-body {
96
+ padding: 16px;
97
+ overflow-y: auto;
98
+ overflow-x: hidden;
99
+ flex: 1;
100
+ min-height: 0;
101
+ }
102
+
103
+ .section {
104
+ margin-bottom: 16px;
105
+ }
106
+
107
+ .section:last-child {
108
+ margin-bottom: 0;
109
+ }
110
+ `,
111
+ ];
112
+
113
+ @property({ attribute: false })
114
+ wallet: DevWallet | null = null;
115
+
116
+ @state()
117
+ private _isOpen = false;
118
+
119
+ #ctrl = new WalletController(this);
120
+ #hadPendingRequest = false;
121
+
122
+ override willUpdate(changedProperties: Map<string, unknown>) {
123
+ if (changedProperties.has('wallet')) {
124
+ this.#ctrl.wallet = this.wallet;
125
+ }
126
+ }
127
+
128
+ override updated() {
129
+ // Refresh balances only when transitioning from having a pending request to not
130
+ const hasPending = this.#ctrl.pendingRequest !== null;
131
+ if (this.#hadPendingRequest && !hasPending) {
132
+ this.updateComplete.then(() => {
133
+ this.shadowRoot
134
+ ?.querySelector<
135
+ import('./dev-wallet-balances.js').DevWalletBalances
136
+ >('dev-wallet-balances')
137
+ ?.refresh();
138
+ });
139
+ }
140
+ this.#hadPendingRequest = hasPending;
141
+
142
+ const dialog = this.shadowRoot?.querySelector<HTMLDialogElement>('.connect-dialog');
143
+ if (this.#ctrl.pendingConnect && dialog && !dialog.open) {
144
+ dialog.showModal();
145
+ } else if (!this.#ctrl.pendingConnect && dialog?.open) {
146
+ dialog.close();
147
+ }
148
+ }
149
+
150
+ override render() {
151
+ return html`
152
+ ${this._isOpen ? this.#renderSidebar() : nothing}
153
+ <button
154
+ class="trigger"
155
+ part="trigger"
156
+ aria-label="Open Dev Wallet"
157
+ @click=${this.#togglePanel}
158
+ >
159
+ ${this.#walletIcon}
160
+ </button>
161
+ ${this.#ctrl.renderSigningModal()} ${this.#ctrl.renderConnectPicker()}
162
+ `;
163
+ }
164
+
165
+ #renderSidebar() {
166
+ return html`
167
+ <div class="sidebar" part="sidebar">
168
+ <div class="sidebar-header">
169
+ <span class="sidebar-title">${this.wallet?.name ?? 'Dev Wallet'}</span>
170
+ ${this.#ctrl.renderNetworkBadge()}
171
+ <button
172
+ class="close-btn"
173
+ part="close-button"
174
+ aria-label="Close"
175
+ @click=${this.#togglePanel}
176
+ >
177
+ &times;
178
+ </button>
179
+ </div>
180
+ <div class="sidebar-body">${this.#ctrl.renderTabContent()}</div>
181
+ ${this.#ctrl.renderTabBar()}
182
+ </div>
183
+ `;
184
+ }
185
+
186
+ get #walletIcon() {
187
+ return html`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
188
+ <rect x="2" y="6" width="20" height="14" rx="2.5" />
189
+ <path d="M2 10h20" />
190
+ <rect x="15" y="12" width="5" height="4" rx="1" />
191
+ <circle cx="17.5" cy="14" r="0.5" fill="currentColor" stroke="none" />
192
+ </svg>`;
193
+ }
194
+
195
+ #togglePanel() {
196
+ this._isOpen = !this._isOpen;
197
+ if (this._isOpen) {
198
+ this.#ctrl.syncState();
199
+ }
200
+ }
201
+ }
202
+
203
+ declare global {
204
+ interface HTMLElementTagNameMap {
205
+ 'dev-wallet-panel': DevWalletPanel;
206
+ }
207
+ }
@@ -0,0 +1,169 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { ClientWithCoreApi } from '@mysten/sui/client';
5
+ import { css, html, LitElement } from 'lit';
6
+ import { customElement, property, state } from 'lit/decorators.js';
7
+
8
+ import type { PendingSigningRequest } from '../wallet/dev-wallet.js';
9
+ import { sharedStyles } from './styles.js';
10
+ import './dev-wallet-connect.js';
11
+ import './dev-wallet-signing.js';
12
+
13
+ @customElement('dev-wallet-popup')
14
+ export class DevWalletPopup extends LitElement {
15
+ static override styles = [
16
+ sharedStyles,
17
+ css`
18
+ :host {
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ min-height: 100vh;
23
+ padding: 20px;
24
+ }
25
+
26
+ .popup-card {
27
+ width: 360px;
28
+ max-height: min(600px, 80vh);
29
+ border-radius: var(--dev-wallet-radius-xl);
30
+ background: var(--dev-wallet-background);
31
+ border: 1px solid var(--dev-wallet-border);
32
+ box-shadow: var(--dev-wallet-shadow-lg);
33
+ overflow: hidden;
34
+ display: flex;
35
+ flex-direction: column;
36
+ }
37
+
38
+ .popup-header {
39
+ display: flex;
40
+ justify-content: space-between;
41
+ align-items: center;
42
+ padding: 14px 16px;
43
+ border-bottom: 1px solid var(--dev-wallet-border);
44
+ }
45
+
46
+ .popup-title {
47
+ font-size: 15px;
48
+ font-weight: var(--dev-wallet-font-weight-semibold);
49
+ color: var(--dev-wallet-foreground);
50
+ }
51
+
52
+ .popup-body {
53
+ flex: 1;
54
+ overflow: hidden;
55
+ display: flex;
56
+ flex-direction: column;
57
+ }
58
+ `,
59
+ ];
60
+
61
+ @property({ type: String })
62
+ walletName = 'Dev Wallet (Web)';
63
+
64
+ @property({ type: String })
65
+ requestType:
66
+ | 'connect'
67
+ | 'sign-transaction'
68
+ | 'sign-and-execute-transaction'
69
+ | 'sign-personal-message' = 'connect';
70
+
71
+ @property({ type: String })
72
+ appName = '';
73
+
74
+ @property({ type: String })
75
+ appUrl = '';
76
+
77
+ @property({ type: String })
78
+ address = '';
79
+
80
+ @property({ type: String })
81
+ accountLabel = '';
82
+
83
+ @property({ type: String })
84
+ chain = '';
85
+
86
+ @property({ attribute: false })
87
+ data: string | Uint8Array | null = null;
88
+
89
+ @property({ attribute: false })
90
+ client: ClientWithCoreApi | null = null;
91
+
92
+ @property({ attribute: false })
93
+ connectAccounts: Array<{ address: string; label?: string; adapterName?: string }> = [];
94
+
95
+ @state()
96
+ private _request: PendingSigningRequest | null = null;
97
+
98
+ #requestId: string | null = null;
99
+
100
+ override willUpdate(changed: Map<string, unknown>) {
101
+ if (
102
+ this.requestType !== 'connect' &&
103
+ (changed.has('requestType') ||
104
+ changed.has('address') ||
105
+ changed.has('accountLabel') ||
106
+ changed.has('chain') ||
107
+ changed.has('data'))
108
+ ) {
109
+ if (!this.#requestId) {
110
+ this.#requestId = crypto.randomUUID();
111
+ }
112
+ this._request = {
113
+ id: this.#requestId,
114
+ type: this.requestType as PendingSigningRequest['type'],
115
+ account: {
116
+ address: this.address,
117
+ label: this.accountLabel || undefined,
118
+ publicKey: new Uint8Array(0),
119
+ chains: [],
120
+ features: [],
121
+ },
122
+ chain: this.chain,
123
+ data: this.data ?? '',
124
+ };
125
+ }
126
+ }
127
+
128
+ override render() {
129
+ return html`
130
+ <div class="popup-card" part="card">
131
+ <div class="popup-header">
132
+ <span class="popup-title">${this.walletName}</span>
133
+ </div>
134
+ <div class="popup-body">
135
+ ${this.requestType === 'connect' ? this.#renderConnect() : this.#renderSigning()}
136
+ </div>
137
+ </div>
138
+ `;
139
+ }
140
+
141
+ #renderConnect() {
142
+ return html`
143
+ <dev-wallet-connect
144
+ exportparts="approve-button: connect-approve-button, reject-button: connect-reject-button, account-list: connect-account-list, error-message: connect-error-message"
145
+ .appName=${this.appName}
146
+ .appUrl=${this.appUrl}
147
+ .accounts=${this.connectAccounts}
148
+ ></dev-wallet-connect>
149
+ `;
150
+ }
151
+
152
+ #renderSigning() {
153
+ if (!this._request) return html``;
154
+
155
+ return html`
156
+ <dev-wallet-signing
157
+ exportparts="approve-button: signing-approve-button, reject-button: signing-reject-button, request-type: signing-request-type, empty-state: signing-empty-state, error-message: signing-error-message, footer: signing-footer"
158
+ .request=${this._request}
159
+ .client=${this.client}
160
+ ></dev-wallet-signing>
161
+ `;
162
+ }
163
+ }
164
+
165
+ declare global {
166
+ interface HTMLElementTagNameMap {
167
+ 'dev-wallet-popup': DevWalletPopup;
168
+ }
169
+ }