@nockchain/rose 0.1.4-nightly.5

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 (205) hide show
  1. package/.github/workflows/artifacts.yml +33 -0
  2. package/.github/workflows/ci.yml +68 -0
  3. package/.github/workflows/publish-sdk.yml +35 -0
  4. package/.nvmrc +1 -0
  5. package/.prettierignore +5 -0
  6. package/.prettierrc +8 -0
  7. package/LICENSE +22 -0
  8. package/README.md +117 -0
  9. package/extension/background/index.ts +1500 -0
  10. package/extension/content/index.ts +59 -0
  11. package/extension/icons/rose.svg +27 -0
  12. package/extension/icons/rose128.png +0 -0
  13. package/extension/icons/rose16.png +0 -0
  14. package/extension/icons/rose256.png +0 -0
  15. package/extension/icons/rose32.png +0 -0
  16. package/extension/icons/rose48.png +0 -0
  17. package/extension/icons/rose512.png +0 -0
  18. package/extension/inpage/index.ts +86 -0
  19. package/extension/manifest.json +48 -0
  20. package/extension/popup/Popup.tsx +94 -0
  21. package/extension/popup/Router.tsx +121 -0
  22. package/extension/popup/assets/arrow-down-icon.svg +3 -0
  23. package/extension/popup/assets/arrow-left-icon.svg +3 -0
  24. package/extension/popup/assets/arrow-right-icon.svg +3 -0
  25. package/extension/popup/assets/arrow-up-icon.svg +3 -0
  26. package/extension/popup/assets/arrow-up-right-icon.svg +3 -0
  27. package/extension/popup/assets/checkmark-icon.svg +3 -0
  28. package/extension/popup/assets/checkmark-pencil-icon.svg +3 -0
  29. package/extension/popup/assets/checkmark-success-icon.svg +3 -0
  30. package/extension/popup/assets/clock-icon.svg +3 -0
  31. package/extension/popup/assets/close-x-icon.svg +3 -0
  32. package/extension/popup/assets/copy-icon.svg +6 -0
  33. package/extension/popup/assets/explorer-icon.svg +3 -0
  34. package/extension/popup/assets/eye-off-icon.svg +3 -0
  35. package/extension/popup/assets/eye-open-icon.svg +4 -0
  36. package/extension/popup/assets/feedback-icon.svg +3 -0
  37. package/extension/popup/assets/green-status-dot.svg +3 -0
  38. package/extension/popup/assets/info-icon.svg +3 -0
  39. package/extension/popup/assets/iris-logo-40.svg +27 -0
  40. package/extension/popup/assets/iris-logo-96.svg +27 -0
  41. package/extension/popup/assets/iris-logo-blue.svg +27 -0
  42. package/extension/popup/assets/iris-logo-no-eye.svg +27 -0
  43. package/extension/popup/assets/iris-logo-orange.svg +27 -0
  44. package/extension/popup/assets/iris-logo.svg +27 -0
  45. package/extension/popup/assets/key-icon.svg +3 -0
  46. package/extension/popup/assets/lock-icon-yellow.svg +3 -0
  47. package/extension/popup/assets/lock-icon.svg +3 -0
  48. package/extension/popup/assets/pencil-edit-icon.svg +3 -0
  49. package/extension/popup/assets/permissions-icon.svg +3 -0
  50. package/extension/popup/assets/receipt-icon.svg +5 -0
  51. package/extension/popup/assets/refresh-icon.svg +3 -0
  52. package/extension/popup/assets/settings-gear-icon.svg +8 -0
  53. package/extension/popup/assets/settings-icon.svg +3 -0
  54. package/extension/popup/assets/theme-icon.svg +3 -0
  55. package/extension/popup/assets/trash-bin-icon.svg +3 -0
  56. package/extension/popup/assets/trend-down-arrow.svg +5 -0
  57. package/extension/popup/assets/trend-up-arrow.svg +5 -0
  58. package/extension/popup/assets/user-account-icon.svg +3 -0
  59. package/extension/popup/assets/vector-bottom-left.svg +9 -0
  60. package/extension/popup/assets/vector-left.svg +9 -0
  61. package/extension/popup/assets/vector-right.svg +9 -0
  62. package/extension/popup/assets/vector-top-right-rotated.svg +8 -0
  63. package/extension/popup/assets/vector-top-right.svg +9 -0
  64. package/extension/popup/assets/wallet-dropdown-arrow.svg +5 -0
  65. package/extension/popup/assets/wallet-icon-style-1.svg +6 -0
  66. package/extension/popup/assets/wallet-icon-style-10.svg +8 -0
  67. package/extension/popup/assets/wallet-icon-style-11.svg +8 -0
  68. package/extension/popup/assets/wallet-icon-style-12.svg +8 -0
  69. package/extension/popup/assets/wallet-icon-style-13.svg +8 -0
  70. package/extension/popup/assets/wallet-icon-style-14.svg +8 -0
  71. package/extension/popup/assets/wallet-icon-style-15.svg +8 -0
  72. package/extension/popup/assets/wallet-icon-style-2.svg +8 -0
  73. package/extension/popup/assets/wallet-icon-style-3.svg +8 -0
  74. package/extension/popup/assets/wallet-icon-style-4.svg +8 -0
  75. package/extension/popup/assets/wallet-icon-style-5.svg +8 -0
  76. package/extension/popup/assets/wallet-icon-style-6.svg +8 -0
  77. package/extension/popup/assets/wallet-icon-style-7.svg +8 -0
  78. package/extension/popup/assets/wallet-icon-style-8.svg +8 -0
  79. package/extension/popup/assets/wallet-icon-style-9.svg +8 -0
  80. package/extension/popup/components/AccountIcon.tsx +78 -0
  81. package/extension/popup/components/AccountSelector.tsx +246 -0
  82. package/extension/popup/components/Alert.tsx +48 -0
  83. package/extension/popup/components/ConfirmModal.tsx +81 -0
  84. package/extension/popup/components/PasswordInput.tsx +49 -0
  85. package/extension/popup/components/ScreenContainer.tsx +17 -0
  86. package/extension/popup/components/SiteIcon.tsx +60 -0
  87. package/extension/popup/components/ThemeToggle.tsx +44 -0
  88. package/extension/popup/components/icons/ArrowDownLeftIcon.tsx +20 -0
  89. package/extension/popup/components/icons/ArrowUpRightIcon.tsx +20 -0
  90. package/extension/popup/components/icons/CheckIcon.tsx +20 -0
  91. package/extension/popup/components/icons/ChevronDownIcon.tsx +15 -0
  92. package/extension/popup/components/icons/ChevronLeftIcon.tsx +15 -0
  93. package/extension/popup/components/icons/ChevronRightIcon.tsx +15 -0
  94. package/extension/popup/components/icons/ChevronUpIcon.tsx +15 -0
  95. package/extension/popup/components/icons/CloseIcon.tsx +26 -0
  96. package/extension/popup/components/icons/CopyIcon.tsx +20 -0
  97. package/extension/popup/components/icons/EditIcon.tsx +20 -0
  98. package/extension/popup/components/icons/EyeIcon.tsx +13 -0
  99. package/extension/popup/components/icons/EyeOffIcon.tsx +13 -0
  100. package/extension/popup/components/icons/InfoIcon.tsx +20 -0
  101. package/extension/popup/components/icons/LockIcon.tsx +20 -0
  102. package/extension/popup/components/icons/PlusIcon.tsx +15 -0
  103. package/extension/popup/components/icons/ReceiveArrowIcon.tsx +14 -0
  104. package/extension/popup/components/icons/ReceiveCircleIcon.tsx +20 -0
  105. package/extension/popup/components/icons/SendPaperPlaneIcon.tsx +18 -0
  106. package/extension/popup/components/icons/SentArrowIcon.tsx +21 -0
  107. package/extension/popup/components/icons/SettingsIcon.tsx +26 -0
  108. package/extension/popup/components/icons/ShieldIcon.tsx +20 -0
  109. package/extension/popup/components/icons/UploadIcon.tsx +20 -0
  110. package/extension/popup/components/icons/WalletIcon.tsx +20 -0
  111. package/extension/popup/contexts/ThemeContext.tsx +105 -0
  112. package/extension/popup/hooks/useApprovalDetection.ts +128 -0
  113. package/extension/popup/hooks/useAutoFocus.ts +36 -0
  114. package/extension/popup/hooks/useAutoRejectOnClose.ts +25 -0
  115. package/extension/popup/hooks/useClickOutside.ts +33 -0
  116. package/extension/popup/hooks/useCopyToClipboard.ts +33 -0
  117. package/extension/popup/hooks/useFavicon.ts +64 -0
  118. package/extension/popup/hooks/useNumericInput.ts +93 -0
  119. package/extension/popup/index.html +13 -0
  120. package/extension/popup/index.tsx +24 -0
  121. package/extension/popup/screens/AboutScreen.tsx +118 -0
  122. package/extension/popup/screens/HomeScreen.tailwind.css +85 -0
  123. package/extension/popup/screens/HomeScreen.tsx +902 -0
  124. package/extension/popup/screens/KeySettingsPasswordScreen.tsx +164 -0
  125. package/extension/popup/screens/LockTimeScreen.tsx +155 -0
  126. package/extension/popup/screens/ReceiveScreen.tsx +149 -0
  127. package/extension/popup/screens/RecoveryPhraseScreen.tsx +183 -0
  128. package/extension/popup/screens/SendReviewScreen.tsx +308 -0
  129. package/extension/popup/screens/SendScreen.tsx +825 -0
  130. package/extension/popup/screens/SendSubmittedScreen.tsx +193 -0
  131. package/extension/popup/screens/SettingsScreen.tsx +116 -0
  132. package/extension/popup/screens/ThemeSettingsScreen.tsx +107 -0
  133. package/extension/popup/screens/TransactionDetailsScreen.tsx +346 -0
  134. package/extension/popup/screens/ViewSecretPhraseScreen.tsx +212 -0
  135. package/extension/popup/screens/WalletPermissionsScreen.tsx +123 -0
  136. package/extension/popup/screens/WalletSettingsScreen.tsx +381 -0
  137. package/extension/popup/screens/WalletStylingScreen.tsx +306 -0
  138. package/extension/popup/screens/approvals/ConnectApprovalScreen.tsx +136 -0
  139. package/extension/popup/screens/approvals/SignMessageScreen.tsx +140 -0
  140. package/extension/popup/screens/approvals/SignRawTxScreen.tsx +320 -0
  141. package/extension/popup/screens/approvals/TransactionApprovalScreen.tsx +167 -0
  142. package/extension/popup/screens/onboarding/BackupScreen.tsx +254 -0
  143. package/extension/popup/screens/onboarding/CreateScreen.tsx +273 -0
  144. package/extension/popup/screens/onboarding/ImportScreen.tsx +676 -0
  145. package/extension/popup/screens/onboarding/ImportScreenV0.tsx +678 -0
  146. package/extension/popup/screens/onboarding/ImportSuccessScreen.tsx +236 -0
  147. package/extension/popup/screens/onboarding/ResumeBackupScreen.tsx +166 -0
  148. package/extension/popup/screens/onboarding/StartScreen.tsx +142 -0
  149. package/extension/popup/screens/onboarding/SuccessScreen.tsx +193 -0
  150. package/extension/popup/screens/onboarding/VerifyScreen.tsx +220 -0
  151. package/extension/popup/screens/system/LockedScreen.tsx +288 -0
  152. package/extension/popup/screens/transactions/ReceiveScreen.tsx +84 -0
  153. package/extension/popup/screens/transactions/SentScreen.tsx +138 -0
  154. package/extension/popup/store.ts +482 -0
  155. package/extension/popup/styles.css +246 -0
  156. package/extension/popup/utils/format.ts +58 -0
  157. package/extension/popup/utils/formatWalletError.ts +36 -0
  158. package/extension/popup/utils/memo.ts +299 -0
  159. package/extension/popup/utils/messaging.ts +16 -0
  160. package/extension/shared/address-encoding.ts +69 -0
  161. package/extension/shared/balance-query.ts +123 -0
  162. package/extension/shared/constants.ts +386 -0
  163. package/extension/shared/currency.ts +128 -0
  164. package/extension/shared/first-name-derivation.ts +128 -0
  165. package/extension/shared/keyfile.ts +58 -0
  166. package/extension/shared/onboarding.ts +78 -0
  167. package/extension/shared/price-api.ts +79 -0
  168. package/extension/shared/rpc-client-browser.ts +315 -0
  169. package/extension/shared/transaction-builder.ts +443 -0
  170. package/extension/shared/types.ts +450 -0
  171. package/extension/shared/utxo-diff.ts +212 -0
  172. package/extension/shared/utxo-store.ts +548 -0
  173. package/extension/shared/utxo-sync.ts +343 -0
  174. package/extension/shared/validators.ts +26 -0
  175. package/extension/shared/vault.ts +1580 -0
  176. package/extension/shared/wallet-crypto.ts +77 -0
  177. package/extension/shared/wasm-utils.ts +76 -0
  178. package/extension/shared/webcrypto.ts +67 -0
  179. package/extension/types/wasm.d.ts +13 -0
  180. package/package.json +39 -0
  181. package/postcss.config.js +6 -0
  182. package/rose-extension-dist.zip +0 -0
  183. package/sdk/README.md +88 -0
  184. package/sdk/examples/app.ts +166 -0
  185. package/sdk/examples/index.html +51 -0
  186. package/sdk/examples/tsconfig.json +15 -0
  187. package/sdk/examples/tx-builder.html +532 -0
  188. package/sdk/examples/tx-builder.ts +1766 -0
  189. package/sdk/package-lock.json +424 -0
  190. package/sdk/package.json +68 -0
  191. package/sdk/src/constants.ts +28 -0
  192. package/sdk/src/errors.ts +74 -0
  193. package/sdk/src/hooks/index.ts +1 -0
  194. package/sdk/src/hooks/use-rose.ts +94 -0
  195. package/sdk/src/index.ts +12 -0
  196. package/sdk/src/provider.ts +396 -0
  197. package/sdk/src/transaction.ts +163 -0
  198. package/sdk/src/types/rose-wasm.d.ts +14 -0
  199. package/sdk/src/types.ts +97 -0
  200. package/sdk/src/wasm.ts +13 -0
  201. package/sdk/tsconfig.json +20 -0
  202. package/sdk/vite.config.examples.ts +32 -0
  203. package/tailwind.config.ts +38 -0
  204. package/tsconfig.json +20 -0
  205. package/vite.config.ts +60 -0
@@ -0,0 +1,308 @@
1
+ import { useState } from 'react';
2
+ import { useStore } from '../store';
3
+ import { truncateAddress } from '../utils/format';
4
+ import { AccountIcon } from '../components/AccountIcon';
5
+ import { send } from '../utils/messaging';
6
+ import { INTERNAL_METHODS } from '../../shared/constants';
7
+ import { formatWalletError } from '../utils/formatWalletError';
8
+ import { nockToNick, formatNock, formatNick } from '../../shared/currency';
9
+ import { ChevronLeftIcon } from '../components/icons/ChevronLeftIcon';
10
+ import { ChevronRightIcon } from '../components/icons/ChevronRightIcon';
11
+
12
+ export function SendReviewScreen() {
13
+ const { navigate, wallet, lastTransaction, priceUsd } = useStore();
14
+
15
+ // If no transaction data, go back to send screen
16
+ if (!lastTransaction) {
17
+ navigate('send');
18
+ return null;
19
+ }
20
+
21
+ const currentAccount = wallet.currentAccount;
22
+
23
+ // Format amounts for display
24
+ const amount = formatNock(lastTransaction.amount);
25
+ const amountInNicks = nockToNick(lastTransaction.amount);
26
+ const feeInNocks = formatNock(lastTransaction.fee);
27
+ const feeInNicks = nockToNick(lastTransaction.fee);
28
+ const total = formatNock(lastTransaction.amount + lastTransaction.fee);
29
+ const totalInNicks = nockToNick(lastTransaction.amount + lastTransaction.fee);
30
+ const remainingBalance = formatNock(
31
+ wallet.balance - lastTransaction.amount - lastTransaction.fee
32
+ );
33
+ const fromAddress = truncateAddress(lastTransaction.from);
34
+ const toAddress = truncateAddress(lastTransaction.to);
35
+
36
+ const [isSending, setIsSending] = useState(false);
37
+ const [error, setError] = useState('');
38
+
39
+ function handleBack() {
40
+ navigate('send');
41
+ }
42
+ function handleCancel() {
43
+ navigate('send');
44
+ }
45
+
46
+ async function handleSend() {
47
+ if (!lastTransaction) return;
48
+
49
+ setIsSending(true);
50
+ setError('');
51
+
52
+ try {
53
+ const amountInNicks = nockToNick(lastTransaction.amount);
54
+ const feeInNicks = nockToNick(lastTransaction.fee);
55
+
56
+ // Send transaction using V2 (builds, locks notes, broadcasts atomically)
57
+ // If sendMax is true, this is a sweep transaction (all UTXOs to recipient)
58
+ const result = await send<{
59
+ txid?: string;
60
+ broadcasted?: boolean;
61
+ walletTx?: any;
62
+ error?: string;
63
+ }>(INTERNAL_METHODS.SEND_TRANSACTION_V2, [
64
+ lastTransaction.to,
65
+ amountInNicks,
66
+ feeInNicks,
67
+ lastTransaction.sendMax, // Pass sendMax flag for sweep transactions
68
+ priceUsd, // Store USD price at time of transaction for historical display
69
+ ]);
70
+
71
+ if (result?.error) {
72
+ setError(formatWalletError(result.error));
73
+ setIsSending(false);
74
+ return;
75
+ }
76
+
77
+ if (result?.txid) {
78
+ // Update lastTransaction with txid
79
+ useStore.getState().setLastTransaction({
80
+ ...lastTransaction,
81
+ txid: result.txid,
82
+ });
83
+
84
+ // Transaction is tracked in WalletTransaction store by sendTransactionV2
85
+ // Refresh balance and transactions from UTXO store
86
+ useStore.getState().fetchBalance();
87
+ useStore.getState().fetchWalletTransactions();
88
+
89
+ // Navigate to success screen
90
+ navigate('send-submitted');
91
+ }
92
+ } catch (err) {
93
+ console.error('[SendReview] Error sending transaction:', err);
94
+ setError(err instanceof Error ? err.message : 'Failed to send transaction');
95
+ setIsSending(false);
96
+ }
97
+ }
98
+
99
+ return (
100
+ <div
101
+ className="w-[357px] h-[600px] flex flex-col"
102
+ style={{ backgroundColor: 'var(--color-bg)', color: 'var(--color-text-primary)' }}
103
+ >
104
+ {/* Header */}
105
+ <header
106
+ className="flex items-center justify-between px-4 py-3 min-h-[64px]"
107
+ style={{ backgroundColor: 'var(--color-bg)' }}
108
+ >
109
+ <button
110
+ type="button"
111
+ onClick={handleBack}
112
+ aria-label="Back"
113
+ className="w-8 h-8 rounded-lg p-2 flex items-center justify-center transition-colors focus:outline-none focus-visible:ring-2"
114
+ style={{ backgroundColor: 'transparent' }}
115
+ onMouseEnter={e => (e.currentTarget.style.backgroundColor = 'var(--color-surface-800)')}
116
+ onMouseLeave={e => (e.currentTarget.style.backgroundColor = 'transparent')}
117
+ >
118
+ <ChevronLeftIcon className="w-5 h-5" />
119
+ </button>
120
+ <h1 className="m-0 text-base font-medium leading-[22px] tracking-[0.16px]">Review</h1>
121
+ <div className="w-8 h-8" />
122
+ </header>
123
+
124
+ {/* Content */}
125
+ <div
126
+ className="flex flex-col justify-between h-[536px]"
127
+ style={{ backgroundColor: 'var(--color-bg)' }}
128
+ >
129
+ <div className="flex flex-col gap-8 px-4 py-2">
130
+ {/* Amount Section */}
131
+ <div className="flex flex-col items-center gap-3 w-full">
132
+ <div
133
+ className="w-10 h-10 rounded-lg grid place-items-center"
134
+ style={{ backgroundColor: 'var(--color-surface-800)' }}
135
+ >
136
+ <AccountIcon
137
+ styleId={currentAccount?.iconStyleId}
138
+ color={currentAccount?.iconColor}
139
+ className="w-6 h-6"
140
+ />
141
+ </div>
142
+ <div className="flex flex-col items-center gap-0.5 w-full text-center">
143
+ <h2 className="m-0 font-[Lora] text-[36px] font-semibold leading-10 tracking-[-0.72px]">
144
+ {amount} <span style={{ color: 'var(--color-text-muted)' }}>NOCK</span>
145
+ </h2>
146
+ <p
147
+ className="m-0 text-[10px] leading-3 tracking-[0.02em]"
148
+ style={{ color: 'var(--color-text-muted)' }}
149
+ >
150
+ {formatNick(amountInNicks)} nicks
151
+ </p>
152
+ </div>
153
+ </div>
154
+
155
+ {/* Details */}
156
+ <div className="flex flex-col gap-2 w-full">
157
+ {/* From/To */}
158
+ <div
159
+ className="rounded-lg p-3 flex items-center gap-2.5"
160
+ style={{ backgroundColor: 'var(--color-surface-800)' }}
161
+ >
162
+ <div className="flex-1 flex flex-col gap-1 min-w-0">
163
+ <div className="text-sm font-medium leading-[18px] tracking-[0.14px]">From</div>
164
+ <div
165
+ className="text-[13px] leading-[18px] tracking-[0.26px] truncate"
166
+ style={{ color: 'var(--color-text-muted)' }}
167
+ >
168
+ {fromAddress}
169
+ </div>
170
+ </div>
171
+ <div className="p-1 shrink-0">
172
+ <ChevronRightIcon className="w-4 h-4" />
173
+ </div>
174
+ <div className="flex-1 flex flex-col gap-1 min-w-0">
175
+ <div className="text-sm font-medium leading-[18px] tracking-[0.14px]">To</div>
176
+ <div
177
+ className="text-[13px] leading-[18px] tracking-[0.26px] truncate"
178
+ style={{ color: 'var(--color-text-muted)' }}
179
+ >
180
+ {toAddress}
181
+ </div>
182
+ </div>
183
+ </div>
184
+
185
+ {/* Network fee & Total */}
186
+ <div className="rounded-lg p-3" style={{ backgroundColor: 'var(--color-surface-800)' }}>
187
+ <div className="flex flex-col gap-2.5 w-full">
188
+ {/* Fee row */}
189
+ <div className="flex items-center justify-between w-full">
190
+ <div className="text-sm font-medium leading-[18px] tracking-[0.14px]">
191
+ Network fee
192
+ </div>
193
+ <div className="flex flex-col items-end">
194
+ <div className="text-sm font-medium leading-[18px] tracking-[0.14px]">
195
+ {feeInNocks} NOCK
196
+ </div>
197
+ <div
198
+ className="text-[10px] leading-3 tracking-[0.02em]"
199
+ style={{ color: 'var(--color-text-muted)' }}
200
+ >
201
+ {formatNick(feeInNicks)} nicks
202
+ </div>
203
+ </div>
204
+ </div>
205
+
206
+ {/* Divider */}
207
+ <div
208
+ className="w-full h-px"
209
+ style={{ backgroundColor: 'var(--color-surface-700)' }}
210
+ />
211
+
212
+ {/* Total row */}
213
+ <div className="flex items-center justify-between w-full">
214
+ <div className="text-sm font-semibold leading-[18px] tracking-[0.14px]">
215
+ Total
216
+ </div>
217
+ <div className="flex flex-col items-end">
218
+ <div className="text-sm font-semibold leading-[18px] tracking-[0.14px]">
219
+ {total} NOCK
220
+ </div>
221
+ <div
222
+ className="text-[10px] leading-3 tracking-[0.02em]"
223
+ style={{ color: 'var(--color-text-muted)' }}
224
+ >
225
+ {formatNick(totalInNicks)} nicks
226
+ </div>
227
+ </div>
228
+ </div>
229
+ </div>
230
+ </div>
231
+
232
+ {/* Remaining balance */}
233
+ <div
234
+ className="text-center text-[12px] leading-4 font-medium tracking-[0.02em] mt-3"
235
+ style={{ color: 'var(--color-text-muted)' }}
236
+ >
237
+ Balance after: {remainingBalance} NOCK
238
+ </div>
239
+ </div>
240
+
241
+ {/* Error message */}
242
+ {error && (
243
+ <div className="px-4">
244
+ <div
245
+ className="rounded-lg p-3 text-sm"
246
+ style={{ backgroundColor: 'var(--color-surface-800)', color: '#ff6b6b' }}
247
+ >
248
+ {error}
249
+ </div>
250
+ </div>
251
+ )}
252
+ </div>
253
+
254
+ {/* DEV: Download signed transaction button */}
255
+ {/* {builtTx?.protobufTx && (
256
+ <div className="px-4 pb-2">
257
+ <button
258
+ type="button"
259
+ onClick={handleDownloadTx}
260
+ className="w-full rounded-lg p-3 flex items-center justify-center transition-opacity hover:opacity-80"
261
+ style={{ backgroundColor: 'var(--color-surface-800)' }}
262
+ >
263
+ <span
264
+ className="text-sm font-medium leading-[18px] tracking-[0.14px]"
265
+ style={{ color: 'var(--color-text-primary)' }}
266
+ >
267
+ Download Signed Transaction (Dev)
268
+ </span>
269
+ </button>
270
+ </div>
271
+ )} */}
272
+
273
+ {/* Actions */}
274
+ <div
275
+ className="flex flex-col gap-2 px-4 py-3"
276
+ style={{ borderTop: '1px solid var(--color-divider)' }}
277
+ >
278
+ <div className="flex gap-3">
279
+ <button
280
+ type="button"
281
+ onClick={handleCancel}
282
+ className="flex-1 h-12 inline-flex items-center justify-center rounded-lg text-sm font-medium leading-[18px] tracking-[0.14px] transition-opacity focus:outline-none focus-visible:ring-2"
283
+ style={{
284
+ backgroundColor: 'var(--color-surface-800)',
285
+ color: 'var(--color-text-primary)',
286
+ }}
287
+ onMouseEnter={e => (e.currentTarget.style.opacity = '0.9')}
288
+ onMouseLeave={e => (e.currentTarget.style.opacity = '1')}
289
+ >
290
+ Cancel
291
+ </button>
292
+ <button
293
+ type="button"
294
+ onClick={handleSend}
295
+ disabled={isSending}
296
+ className="flex-1 h-12 inline-flex items-center justify-center rounded-lg text-sm font-medium leading-[18px] tracking-[0.14px] transition-opacity focus:outline-none focus-visible:ring-2"
297
+ style={{ backgroundColor: 'var(--color-primary)', color: '#000' }}
298
+ onMouseEnter={e => (e.currentTarget.style.opacity = '0.9')}
299
+ onMouseLeave={e => (e.currentTarget.style.opacity = '1')}
300
+ >
301
+ {isSending ? 'Sending...' : 'Send'}
302
+ </button>
303
+ </div>
304
+ </div>
305
+ </div>
306
+ </div>
307
+ );
308
+ }