@hivemindhq/core 0.4.0 → 0.5.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 (85) hide show
  1. package/README.md +16 -16
  2. package/dist/{chunk-2RGM3KJL.js → chunk-K2544PJ5.js} +42 -20
  3. package/dist/chunk-K2544PJ5.js.map +1 -0
  4. package/dist/{chunk-P5E2XNDI.js → chunk-K4XDMY2V.js} +3 -3
  5. package/dist/{chunk-P5E2XNDI.js.map → chunk-K4XDMY2V.js.map} +1 -1
  6. package/dist/{chunk-ERZSVDIB.js → chunk-RW4JXOAM.js} +11 -3
  7. package/dist/chunk-RW4JXOAM.js.map +1 -0
  8. package/dist/chunk-VU3OPG32.js +907 -0
  9. package/dist/chunk-VU3OPG32.js.map +1 -0
  10. package/dist/components/index.d.ts +28 -3
  11. package/dist/components/index.js +2 -2
  12. package/dist/components/ui/index.js +2 -2
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +6 -6
  15. package/dist/utils/index.d.ts +312 -6
  16. package/dist/utils/index.js +2 -2
  17. package/package.json +15 -11
  18. package/src/components/AtomIcon.tsx +21 -0
  19. package/src/components/CryptoAmount.tsx +447 -0
  20. package/src/components/ErrorBanner.tsx +35 -0
  21. package/src/components/IpfsImage.tsx +21 -0
  22. package/src/components/LoadingDots.tsx +55 -0
  23. package/src/components/TripleAreaChart.tsx +108 -0
  24. package/src/components/TriplePositionsTornadoMinGraph.tsx +71 -0
  25. package/src/components/UnknownImage.tsx +55 -0
  26. package/src/components/index.ts +24 -0
  27. package/src/components/ui/alert.tsx +59 -0
  28. package/src/components/ui/avatar.tsx +47 -0
  29. package/src/components/ui/badge.tsx +35 -0
  30. package/src/components/ui/breadcrumb.tsx +108 -0
  31. package/src/components/ui/button.tsx +56 -0
  32. package/src/components/ui/card.tsx +75 -0
  33. package/src/components/ui/carousel.tsx +239 -0
  34. package/src/components/ui/chart.tsx +350 -0
  35. package/src/components/ui/checkbox.tsx +28 -0
  36. package/src/components/ui/collapsible.tsx +10 -0
  37. package/src/components/ui/command.tsx +177 -0
  38. package/src/components/ui/dialog.tsx +119 -0
  39. package/src/components/ui/dropdown-menu.tsx +202 -0
  40. package/src/components/ui/form.tsx +175 -0
  41. package/src/components/ui/index.ts +183 -0
  42. package/src/components/ui/input.tsx +21 -0
  43. package/src/components/ui/label.tsx +25 -0
  44. package/src/components/ui/loader.tsx +20 -0
  45. package/src/components/ui/pagination.tsx +104 -0
  46. package/src/components/ui/popover.tsx +45 -0
  47. package/src/components/ui/progress.tsx +25 -0
  48. package/src/components/ui/radio-group.tsx +42 -0
  49. package/src/components/ui/scroll-area.tsx +45 -0
  50. package/src/components/ui/select.tsx +178 -0
  51. package/src/components/ui/separator.tsx +28 -0
  52. package/src/components/ui/sheet.tsx +139 -0
  53. package/src/components/ui/sidebar.tsx +723 -0
  54. package/src/components/ui/skeleton.tsx +15 -0
  55. package/src/components/ui/sonner.tsx +27 -0
  56. package/src/components/ui/spinner.tsx +67 -0
  57. package/src/components/ui/switch.tsx +26 -0
  58. package/src/components/ui/table.tsx +113 -0
  59. package/src/components/ui/tabs.tsx +63 -0
  60. package/src/components/ui/textarea.tsx +21 -0
  61. package/src/components/ui/toast.tsx +146 -0
  62. package/src/components/ui/toaster.tsx +33 -0
  63. package/src/components/ui/toggle-group.tsx +58 -0
  64. package/src/components/ui/toggle.tsx +44 -0
  65. package/src/components/ui/tooltip.tsx +61 -0
  66. package/src/hooks/index.ts +7 -0
  67. package/src/hooks/use-mobile.ts +20 -0
  68. package/src/hooks/use-toast.ts +190 -0
  69. package/src/index.ts +25 -0
  70. package/src/types/index.ts +17 -0
  71. package/src/utils/atom-label-detection.ts +689 -0
  72. package/src/utils/atom.ts +279 -0
  73. package/src/utils/cn.ts +18 -0
  74. package/src/utils/formatting.ts +624 -0
  75. package/src/utils/index.ts +11 -0
  76. package/src/utils/multivault-errors.ts +581 -0
  77. package/src/utils/search/formatting.tsx +95 -0
  78. package/src/utils/search/index.ts +28 -0
  79. package/src/utils/search/ranking.ts +203 -0
  80. package/src/utils/search/types.ts +114 -0
  81. package/tailwind.config.js +3 -3
  82. package/dist/chunk-2RGM3KJL.js.map +0 -1
  83. package/dist/chunk-ERZSVDIB.js.map +0 -1
  84. package/dist/chunk-H4RMZQ2Z.js +0 -213
  85. package/dist/chunk-H4RMZQ2Z.js.map +0 -1
@@ -0,0 +1,581 @@
1
+ /**
2
+ * MultiVault Contract Error Mappings
3
+ *
4
+ * Maps Solidity error names from the MultiVault contract to user-friendly messages.
5
+ * These errors are thrown by the Intuition Protocol's MultiVault contract.
6
+ *
7
+ * @see intuition-contracts-v2/src/protocol/MultiVault.sol
8
+ * @see intuition-contracts-v2/src/protocol/MultiVaultCore.sol
9
+ */
10
+
11
+ export interface MultiVaultErrorInfo {
12
+ /** The Solidity error name as it appears in the contract */
13
+ errorName: string
14
+ /** User-friendly message to display in the UI */
15
+ userMessage: string
16
+ /** More detailed explanation for tooltips or error details */
17
+ description: string
18
+ /** Category for grouping/filtering errors */
19
+ category:
20
+ | 'atom'
21
+ | 'triple'
22
+ | 'deposit'
23
+ | 'redeem'
24
+ | 'balance'
25
+ | 'limits'
26
+ | 'batch'
27
+ | 'approval'
28
+ | 'existence'
29
+ | 'epoch'
30
+ | 'wallet'
31
+ | 'internal'
32
+ /** Whether this error is commonly encountered by users */
33
+ isCommon: boolean
34
+ }
35
+
36
+ /**
37
+ * Result of parsing a MultiVault error
38
+ */
39
+ export interface ParsedMultiVaultError {
40
+ /** User-friendly message to display in the UI */
41
+ userMessage: string
42
+ /** More detailed explanation for tooltips or error details */
43
+ description: string
44
+ /** Whether this error is commonly encountered by users */
45
+ isCommon: boolean
46
+ /** The original error name if matched, undefined if fallback */
47
+ errorName?: string
48
+ /** The error category if matched */
49
+ category?: MultiVaultErrorInfo['category']
50
+ /** Whether this was a known MultiVault error */
51
+ isMultiVaultError: boolean
52
+ }
53
+
54
+ /**
55
+ * Complete mapping of MultiVault contract errors to user-friendly messages.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const errorInfo = MULTIVAULT_ERRORS['MultiVault_AtomExists']
60
+ * toast.error(errorInfo.userMessage)
61
+ * ```
62
+ */
63
+ export const MULTIVAULT_ERRORS: Record<string, MultiVaultErrorInfo> = {
64
+ // ============================================
65
+ // ATOM CREATION ERRORS
66
+ // ============================================
67
+
68
+ MultiVault_AtomExists: {
69
+ errorName: 'MultiVault_AtomExists',
70
+ userMessage: 'This entity already exists on-chain',
71
+ description:
72
+ 'An atom with this exact data has already been created. You can stake on the existing atom instead.',
73
+ category: 'atom',
74
+ isCommon: true,
75
+ },
76
+
77
+ MultiVault_AtomDoesNotExist: {
78
+ errorName: 'MultiVault_AtomDoesNotExist',
79
+ userMessage: "This entity hasn't been created yet",
80
+ description:
81
+ 'The atom you are trying to reference does not exist on-chain. It may need to be created first.',
82
+ category: 'atom',
83
+ isCommon: true,
84
+ },
85
+
86
+ MultiVault_NoAtomDataProvided: {
87
+ errorName: 'MultiVault_NoAtomDataProvided',
88
+ userMessage: 'No data provided for entity creation',
89
+ description:
90
+ 'Atom creation requires data (URL, IPFS URI, or other identifier) to be provided.',
91
+ category: 'atom',
92
+ isCommon: false,
93
+ },
94
+
95
+ MultiVault_AtomDataTooLong: {
96
+ errorName: 'MultiVault_AtomDataTooLong',
97
+ userMessage: 'Entity data is too large',
98
+ description:
99
+ 'The provided atom data exceeds the maximum allowed length. Consider using an IPFS URI instead.',
100
+ category: 'atom',
101
+ isCommon: false,
102
+ },
103
+
104
+ // ============================================
105
+ // TRIPLE CREATION ERRORS
106
+ // ============================================
107
+
108
+ MultiVault_TripleExists: {
109
+ errorName: 'MultiVault_TripleExists',
110
+ userMessage: 'This claim already exists',
111
+ description:
112
+ 'A triple with this exact subject-predicate-object combination has already been created. You can stake on the existing claim instead.',
113
+ category: 'triple',
114
+ isCommon: true,
115
+ },
116
+
117
+ MultiVault_TermNotTriple: {
118
+ errorName: 'MultiVault_TermNotTriple',
119
+ userMessage: 'This is not a claim',
120
+ description:
121
+ 'The specified term ID refers to an atom, not a triple. Triple-specific operations cannot be performed on atoms.',
122
+ category: 'triple',
123
+ isCommon: false,
124
+ },
125
+
126
+ MultiVault_CannotDirectlyInitializeCounterTriple: {
127
+ errorName: 'MultiVault_CannotDirectlyInitializeCounterTriple',
128
+ userMessage: 'Cannot initialize counter position directly',
129
+ description:
130
+ 'Counter-triple vaults are automatically created when the main triple is created. You cannot deposit directly into a counter vault that has not been initialized.',
131
+ category: 'triple',
132
+ isCommon: false,
133
+ },
134
+
135
+ // ============================================
136
+ // DEPOSIT/STAKING ERRORS
137
+ // ============================================
138
+
139
+ MultiVault_HasCounterStake: {
140
+ errorName: 'MultiVault_HasCounterStake',
141
+ userMessage: 'You already have an opposing position. Unstake first.',
142
+ description:
143
+ 'You cannot stake on both sides of a claim simultaneously. Please remove your existing position before staking on the opposite side.',
144
+ category: 'deposit',
145
+ isCommon: true,
146
+ },
147
+
148
+ MultiVault_DepositBelowMinimumDeposit: {
149
+ errorName: 'MultiVault_DepositBelowMinimumDeposit',
150
+ userMessage: 'Deposit amount is below minimum',
151
+ description:
152
+ 'The amount you are trying to deposit is less than the protocol minimum. Please increase your deposit amount.',
153
+ category: 'deposit',
154
+ isCommon: true,
155
+ },
156
+
157
+ MultiVault_DepositOrRedeemZeroShares: {
158
+ errorName: 'MultiVault_DepositOrRedeemZeroShares',
159
+ userMessage: 'Transaction would result in zero shares',
160
+ description:
161
+ 'The deposit amount is too small to mint any shares, or you are trying to redeem zero shares.',
162
+ category: 'deposit',
163
+ isCommon: false,
164
+ },
165
+
166
+ MultiVault_DepositTooSmallToCoverMinShares: {
167
+ errorName: 'MultiVault_DepositTooSmallToCoverMinShares',
168
+ userMessage: 'Deposit too small to initialize vault',
169
+ description:
170
+ 'When initializing a new vault on a non-default bonding curve, the deposit must cover the minimum share cost.',
171
+ category: 'deposit',
172
+ isCommon: false,
173
+ },
174
+
175
+ MultiVault_DefaultCurveMustBeInitializedViaCreatePaths: {
176
+ errorName: 'MultiVault_DefaultCurveMustBeInitializedViaCreatePaths',
177
+ userMessage: 'Vault must be created before depositing',
178
+ description:
179
+ 'Default curve vaults must be initialized through createAtoms or createTriples, not through direct deposits.',
180
+ category: 'deposit',
181
+ isCommon: false,
182
+ },
183
+
184
+ MultiVault_SenderNotApproved: {
185
+ errorName: 'MultiVault_SenderNotApproved',
186
+ userMessage: 'Not authorized to deposit for this account',
187
+ description:
188
+ 'You do not have approval to deposit on behalf of the specified receiver address.',
189
+ category: 'deposit',
190
+ isCommon: false,
191
+ },
192
+
193
+ MultiVault_SlippageExceeded: {
194
+ errorName: 'MultiVault_SlippageExceeded',
195
+ userMessage: 'Price changed. Try again with updated amount.',
196
+ description:
197
+ 'The share price moved unfavorably between when you submitted and when the transaction executed. The actual shares received would be less than your minimum.',
198
+ category: 'deposit',
199
+ isCommon: true,
200
+ },
201
+
202
+ // ============================================
203
+ // REDEMPTION/UNSTAKING ERRORS
204
+ // ============================================
205
+
206
+ MultiVault_InsufficientSharesInVault: {
207
+ errorName: 'MultiVault_InsufficientSharesInVault',
208
+ userMessage: 'Insufficient shares to redeem',
209
+ description:
210
+ 'You are trying to redeem more shares than you currently own in this vault.',
211
+ category: 'redeem',
212
+ isCommon: true,
213
+ },
214
+
215
+ MultiVault_InsufficientRemainingSharesInVault: {
216
+ errorName: 'MultiVault_InsufficientRemainingSharesInVault',
217
+ userMessage: 'Cannot redeem: would leave vault below minimum',
218
+ description:
219
+ 'This redemption would leave the vault with fewer shares than the protocol minimum. You may need to redeem a smaller amount.',
220
+ category: 'redeem',
221
+ isCommon: false,
222
+ },
223
+
224
+ MultiVault_RedeemerNotApproved: {
225
+ errorName: 'MultiVault_RedeemerNotApproved',
226
+ userMessage: 'Not authorized to redeem for this account',
227
+ description:
228
+ 'You do not have approval to redeem shares on behalf of the specified receiver address.',
229
+ category: 'redeem',
230
+ isCommon: false,
231
+ },
232
+
233
+ // ============================================
234
+ // BALANCE/ASSET ERRORS
235
+ // ============================================
236
+
237
+ MultiVault_InsufficientBalance: {
238
+ errorName: 'MultiVault_InsufficientBalance',
239
+ userMessage: 'Insufficient TRUST balance',
240
+ description:
241
+ 'You do not have enough TRUST tokens to complete this transaction. Please add more funds to your wallet.',
242
+ category: 'balance',
243
+ isCommon: true,
244
+ },
245
+
246
+ MultiVault_InsufficientAssets: {
247
+ errorName: 'MultiVault_InsufficientAssets',
248
+ userMessage: 'Not enough funds for this operation',
249
+ description:
250
+ 'The assets provided are less than the required cost for this operation (atom/triple creation cost + deposit).',
251
+ category: 'balance',
252
+ isCommon: true,
253
+ },
254
+
255
+ MultiVault_BurnFromZeroAddress: {
256
+ errorName: 'MultiVault_BurnFromZeroAddress',
257
+ userMessage: 'Transaction failed',
258
+ description:
259
+ 'Internal error: attempted to burn shares from the zero address.',
260
+ category: 'internal',
261
+ isCommon: false,
262
+ },
263
+
264
+ MultiVault_BurnInsufficientBalance: {
265
+ errorName: 'MultiVault_BurnInsufficientBalance',
266
+ userMessage: 'Transaction failed',
267
+ description:
268
+ 'Internal error: attempted to burn more shares than the account holds.',
269
+ category: 'internal',
270
+ isCommon: false,
271
+ },
272
+
273
+ // ============================================
274
+ // LIMIT/BOUNDS ERRORS
275
+ // ============================================
276
+
277
+ MultiVault_ActionExceedsMaxAssets: {
278
+ errorName: 'MultiVault_ActionExceedsMaxAssets',
279
+ userMessage: 'Vault is at maximum capacity',
280
+ description:
281
+ 'This deposit would cause the vault to exceed its maximum allowed assets. The vault cannot accept more deposits.',
282
+ category: 'limits',
283
+ isCommon: false,
284
+ },
285
+
286
+ MultiVault_ActionExceedsMaxShares: {
287
+ errorName: 'MultiVault_ActionExceedsMaxShares',
288
+ userMessage: 'Vault is at maximum capacity',
289
+ description:
290
+ 'This deposit would cause the vault to exceed its maximum allowed shares. The vault cannot accept more deposits.',
291
+ category: 'limits',
292
+ isCommon: false,
293
+ },
294
+
295
+ // ============================================
296
+ // ARRAY/BATCH ERRORS
297
+ // ============================================
298
+
299
+ MultiVault_ArraysNotSameLength: {
300
+ errorName: 'MultiVault_ArraysNotSameLength',
301
+ userMessage: 'Invalid batch operation',
302
+ description:
303
+ 'The arrays provided for this batch operation have different lengths. All arrays must have the same number of elements.',
304
+ category: 'batch',
305
+ isCommon: false,
306
+ },
307
+
308
+ MultiVault_InvalidArrayLength: {
309
+ errorName: 'MultiVault_InvalidArrayLength',
310
+ userMessage: 'Invalid number of items in batch',
311
+ description:
312
+ 'The batch operation contains either zero items or exceeds the maximum batch size of 150 items.',
313
+ category: 'batch',
314
+ isCommon: false,
315
+ },
316
+
317
+ // ============================================
318
+ // APPROVAL ERRORS
319
+ // ============================================
320
+
321
+ MultiVault_CannotApproveOrRevokeSelf: {
322
+ errorName: 'MultiVault_CannotApproveOrRevokeSelf',
323
+ userMessage: 'Cannot modify own approval',
324
+ description:
325
+ 'You cannot approve or revoke approval for yourself. Approval is only for allowing other addresses to act on your behalf.',
326
+ category: 'approval',
327
+ isCommon: false,
328
+ },
329
+
330
+ // ============================================
331
+ // TERM EXISTENCE ERRORS
332
+ // ============================================
333
+
334
+ MultiVault_TermDoesNotExist: {
335
+ errorName: 'MultiVault_TermDoesNotExist',
336
+ userMessage: "This entity or claim doesn't exist",
337
+ description:
338
+ 'The specified term (atom or triple) has not been created on-chain. It may have been deleted or never existed.',
339
+ category: 'existence',
340
+ isCommon: true,
341
+ },
342
+
343
+ // ============================================
344
+ // EPOCH/UTILIZATION ERRORS
345
+ // ============================================
346
+
347
+ MultiVault_EpochNotTracked: {
348
+ errorName: 'MultiVault_EpochNotTracked',
349
+ userMessage: 'No activity recorded for this period',
350
+ description:
351
+ 'There is no recorded activity for the specified epoch in the user history.',
352
+ category: 'epoch',
353
+ isCommon: false,
354
+ },
355
+
356
+ MultiVault_InvalidEpoch: {
357
+ errorName: 'MultiVault_InvalidEpoch',
358
+ userMessage: 'Invalid time period',
359
+ description: 'The specified epoch is in the future or otherwise invalid.',
360
+ category: 'epoch',
361
+ isCommon: false,
362
+ },
363
+
364
+ // ============================================
365
+ // WALLET ERRORS
366
+ // ============================================
367
+
368
+ MultiVault_OnlyAssociatedAtomWallet: {
369
+ errorName: 'MultiVault_OnlyAssociatedAtomWallet',
370
+ userMessage: "Only the entity's wallet can claim fees",
371
+ description:
372
+ 'Atom wallet deposit fees can only be claimed by the associated atom wallet contract.',
373
+ category: 'wallet',
374
+ isCommon: false,
375
+ },
376
+
377
+ // ============================================
378
+ // MULTIVAULTCORE ERRORS
379
+ // ============================================
380
+
381
+ MultiVaultCore_InvalidAdmin: {
382
+ errorName: 'MultiVaultCore_InvalidAdmin',
383
+ userMessage: 'Invalid admin address',
384
+ description:
385
+ 'The contract cannot be initialized with a zero address admin.',
386
+ category: 'internal',
387
+ isCommon: false,
388
+ },
389
+
390
+ MultiVaultCore_AtomDoesNotExist: {
391
+ errorName: 'MultiVaultCore_AtomDoesNotExist',
392
+ userMessage: 'Entity not found',
393
+ description:
394
+ 'The specified atom ID does not correspond to any existing atom on-chain.',
395
+ category: 'existence',
396
+ isCommon: true,
397
+ },
398
+
399
+ MultiVaultCore_TripleDoesNotExist: {
400
+ errorName: 'MultiVaultCore_TripleDoesNotExist',
401
+ userMessage: 'Claim not found',
402
+ description:
403
+ 'The specified triple ID does not correspond to any existing triple on-chain.',
404
+ category: 'existence',
405
+ isCommon: true,
406
+ },
407
+
408
+ MultiVaultCore_TermDoesNotExist: {
409
+ errorName: 'MultiVaultCore_TermDoesNotExist',
410
+ userMessage: 'Entity or claim not found',
411
+ description:
412
+ 'The specified term ID does not correspond to any existing atom or triple on-chain.',
413
+ category: 'existence',
414
+ isCommon: true,
415
+ },
416
+ } as const
417
+
418
+ /**
419
+ * All error categories for filtering/grouping
420
+ */
421
+ export const ERROR_CATEGORIES = [
422
+ 'atom',
423
+ 'triple',
424
+ 'deposit',
425
+ 'redeem',
426
+ 'balance',
427
+ 'limits',
428
+ 'batch',
429
+ 'approval',
430
+ 'existence',
431
+ 'epoch',
432
+ 'wallet',
433
+ 'internal',
434
+ ] as const
435
+
436
+ export type ErrorCategory = (typeof ERROR_CATEGORIES)[number]
437
+
438
+ /**
439
+ * Get all errors marked as commonly encountered by users
440
+ */
441
+ export const COMMON_ERRORS = Object.entries(MULTIVAULT_ERRORS)
442
+ .filter(([, info]) => info.isCommon)
443
+ .reduce(
444
+ (acc, [key, value]) => {
445
+ acc[key] = value
446
+ return acc
447
+ },
448
+ {} as Record<string, MultiVaultErrorInfo>
449
+ )
450
+
451
+ /**
452
+ * Total count of mapped errors
453
+ */
454
+ export const TOTAL_ERROR_COUNT = Object.keys(MULTIVAULT_ERRORS).length // 31 errors
455
+
456
+ /**
457
+ * Extract error name from various error formats
458
+ *
459
+ * Handles:
460
+ * - Viem ContractFunctionRevertedError with error.name
461
+ * - Error messages containing error names (e.g., "MultiVault_AtomExists")
462
+ * - Nested error.cause structures
463
+ *
464
+ * @param error - The error object from a contract call
465
+ * @returns The extracted error name or undefined if not found
466
+ */
467
+ function extractErrorName(error: unknown): string | undefined {
468
+ if (!error) return undefined
469
+
470
+ // Type guard for error-like objects
471
+ const isErrorLike = (e: unknown): e is { message?: string; name?: string; cause?: unknown; data?: { errorName?: string } } =>
472
+ typeof e === 'object' && e !== null
473
+
474
+ if (!isErrorLike(error)) return undefined
475
+
476
+ // Check for viem's ContractFunctionRevertedError structure
477
+ // These have error.data.errorName
478
+ if (error.data?.errorName) {
479
+ return error.data.errorName
480
+ }
481
+
482
+ // Check for error.name that matches MultiVault pattern
483
+ if (error.name?.startsWith('MultiVault')) {
484
+ return error.name
485
+ }
486
+
487
+ // Search error message for known error names
488
+ if (error.message) {
489
+ for (const errorName of Object.keys(MULTIVAULT_ERRORS)) {
490
+ if (error.message.includes(errorName)) {
491
+ return errorName
492
+ }
493
+ }
494
+ }
495
+
496
+ // Check nested cause
497
+ if (error.cause) {
498
+ return extractErrorName(error.cause)
499
+ }
500
+
501
+ return undefined
502
+ }
503
+
504
+ /**
505
+ * Parse a contract error and return user-friendly error information
506
+ *
507
+ * This function attempts to match the error against known MultiVault errors
508
+ * and returns structured information for display in the UI.
509
+ *
510
+ * @param error - The error object from a contract call
511
+ * @returns Parsed error information with user-friendly message
512
+ *
513
+ * @example
514
+ * ```typescript
515
+ * try {
516
+ * await createAtom(...)
517
+ * } catch (err) {
518
+ * const parsed = parseMultiVaultError(err)
519
+ * toast.error(parsed.userMessage)
520
+ * if (parsed.isMultiVaultError) {
521
+ * console.log('Contract error:', parsed.errorName)
522
+ * }
523
+ * }
524
+ * ```
525
+ */
526
+ export function parseMultiVaultError(error: unknown): ParsedMultiVaultError {
527
+ const errorName = extractErrorName(error)
528
+
529
+ if (errorName && MULTIVAULT_ERRORS[errorName]) {
530
+ const errorInfo = MULTIVAULT_ERRORS[errorName]
531
+ return {
532
+ userMessage: errorInfo.userMessage,
533
+ description: errorInfo.description,
534
+ isCommon: errorInfo.isCommon,
535
+ errorName: errorInfo.errorName,
536
+ category: errorInfo.category,
537
+ isMultiVaultError: true,
538
+ }
539
+ }
540
+
541
+ // Fallback for unknown errors
542
+ return {
543
+ userMessage: 'Transaction failed',
544
+ description: 'An unexpected error occurred. Please try again.',
545
+ isCommon: false,
546
+ isMultiVaultError: false,
547
+ }
548
+ }
549
+
550
+ /**
551
+ * Check if an error is a specific MultiVault error
552
+ *
553
+ * @param error - The error to check
554
+ * @param errorName - The specific error name to check for
555
+ * @returns True if the error matches the specified error name
556
+ *
557
+ * @example
558
+ * ```typescript
559
+ * if (isMultiVaultError(err, 'MultiVault_AtomExists')) {
560
+ * // Handle atom already exists case
561
+ * }
562
+ * ```
563
+ */
564
+ export function isMultiVaultError(
565
+ error: unknown,
566
+ errorName: keyof typeof MULTIVAULT_ERRORS
567
+ ): boolean {
568
+ const extracted = extractErrorName(error)
569
+ return extracted === errorName
570
+ }
571
+
572
+ /**
573
+ * Check if an error is any known MultiVault error
574
+ *
575
+ * @param error - The error to check
576
+ * @returns True if the error is a known MultiVault error
577
+ */
578
+ export function isKnownMultiVaultError(error: unknown): boolean {
579
+ const extracted = extractErrorName(error)
580
+ return extracted !== undefined && extracted in MULTIVAULT_ERRORS
581
+ }
@@ -0,0 +1,95 @@
1
+ import React from 'react'
2
+
3
+ /**
4
+ * Format stake amount for display (converts from wei to TRUST with suffixes)
5
+ *
6
+ * @param marketCap - The market cap in wei (18 decimals)
7
+ * @returns Formatted string like "1.5K", "2.3M", etc.
8
+ *
9
+ * @example
10
+ * formatStake('1000000000000000000') // "1"
11
+ * formatStake('1500000000000000000000') // "1.5K"
12
+ * formatStake('2300000000000000000000000') // "2.3M"
13
+ */
14
+ export function formatStake(marketCap: string | number | undefined): string {
15
+ if (!marketCap) return '0'
16
+
17
+ // Convert from wei (18 decimals) to TRUST
18
+ const trustValue = Number(BigInt(marketCap)) / 1e18
19
+
20
+ if (trustValue === 0) return '0'
21
+
22
+ // Helper to format with proper decimals and remove trailing zeros
23
+ const formatWithDecimals = (value: number, decimals: number = 2): string => {
24
+ return value.toFixed(decimals).replace(/\.?0+$/, '')
25
+ }
26
+
27
+ // Format in TRUST with K/M/B suffixes
28
+ if (trustValue >= 1e9) {
29
+ return `${formatWithDecimals(trustValue / 1e9, 2)}B`
30
+ } else if (trustValue >= 1e6) {
31
+ return `${formatWithDecimals(trustValue / 1e6, 2)}M`
32
+ } else if (trustValue >= 1e3) {
33
+ return `${formatWithDecimals(trustValue / 1e3, 2)}K`
34
+ } else {
35
+ // For smaller values, show up to 2 decimals
36
+ return formatWithDecimals(trustValue, 2)
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Highlight matching text in search results
42
+ * Returns React elements with highlighted portions
43
+ *
44
+ * @param text - The text to highlight
45
+ * @param searchTerm - The search term to highlight
46
+ * @returns React elements with matching text highlighted
47
+ *
48
+ * @example
49
+ * highlightMatch('Vitalik Buterin', 'vitalik')
50
+ * // Returns: [<strong>Vitalik</strong>, ' Buterin']
51
+ */
52
+ export function highlightMatch(
53
+ text: string,
54
+ searchTerm: string
55
+ ): React.ReactNode {
56
+ if (!text || !searchTerm) return text
57
+
58
+ const regex = new RegExp(`(${escapeRegExp(searchTerm)})`, 'gi')
59
+ const parts = text.split(regex)
60
+
61
+ return parts.map((part, i) =>
62
+ part.toLowerCase() === searchTerm.toLowerCase() ? (
63
+ <strong key={i} className="bg-yellow-500/20 text-yellow-500">
64
+ {part}
65
+ </strong>
66
+ ) : (
67
+ part
68
+ )
69
+ )
70
+ }
71
+
72
+ /**
73
+ * Escape special regex characters in a string
74
+ */
75
+ function escapeRegExp(string: string): string {
76
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
77
+ }
78
+
79
+ /**
80
+ * Format a term_id for display (first 5 characters after 0x)
81
+ *
82
+ * @param termId - The full term_id (e.g., "0x123456789...")
83
+ * @returns Shortened display format (e.g., "12345")
84
+ *
85
+ * @example
86
+ * formatTermId('0x123456789098765432') // "12345"
87
+ */
88
+ export function formatTermId(termId: string): string {
89
+ if (!termId) return ''
90
+ if (termId.startsWith('0x')) {
91
+ return termId.slice(2, 7)
92
+ }
93
+ return termId.slice(0, 5)
94
+ }
95
+
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Search utilities for atom search functionality
3
+ * Shared between hivemind-explorer and intuition-extension
4
+ */
5
+
6
+ // Ranking
7
+ export {
8
+ calculateMatchScore,
9
+ rankAtoms,
10
+ getAtomDisplayName,
11
+ getAtomDescription,
12
+ getAtomImage,
13
+ } from './ranking'
14
+
15
+ // Formatting
16
+ export { formatStake, highlightMatch, formatTermId } from './formatting'
17
+
18
+ // Types
19
+ export type {
20
+ AtomVault,
21
+ AtomValue,
22
+ AtomCreator,
23
+ GraphQLAtom,
24
+ RankedAtom,
25
+ SearchSummary,
26
+ SearchResult,
27
+ } from './types'
28
+