@hot-labs/kit 1.6.0 → 1.6.2

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 (72) hide show
  1. package/build/activity.d.ts +4 -0
  2. package/build/activity.js +20 -1
  3. package/build/activity.js.map +1 -1
  4. package/build/core/defuse.d.ts +61 -0
  5. package/build/core/defuse.js +47 -0
  6. package/build/core/defuse.js.map +1 -0
  7. package/build/core/exchange.d.ts +8 -4
  8. package/build/core/exchange.js +33 -7
  9. package/build/core/exchange.js.map +1 -1
  10. package/build/core/pendings.d.ts +37 -12
  11. package/build/core/pendings.js +70 -35
  12. package/build/core/pendings.js.map +1 -1
  13. package/build/ui/bridge/Bridge.js +11 -186
  14. package/build/ui/bridge/Bridge.js.map +1 -1
  15. package/build/ui/bridge/SelectSender.d.ts +2 -1
  16. package/build/ui/bridge/SelectSender.js +10 -2
  17. package/build/ui/bridge/SelectSender.js.map +1 -1
  18. package/build/ui/bridge/SelectToken.d.ts +2 -1
  19. package/build/ui/bridge/SelectToken.js +14 -6
  20. package/build/ui/bridge/SelectToken.js.map +1 -1
  21. package/build/ui/bridge/TokenAmountCard.d.ts +39 -0
  22. package/build/ui/bridge/TokenAmountCard.js +186 -0
  23. package/build/ui/bridge/TokenAmountCard.js.map +1 -0
  24. package/build/ui/icons/warning.js +1 -1
  25. package/build/ui/icons/warning.js.map +1 -1
  26. package/build/ui/profile/DepositFlow.d.ts +3 -0
  27. package/build/ui/profile/DepositFlow.js +128 -9
  28. package/build/ui/profile/DepositFlow.js.map +1 -1
  29. package/build/ui/profile/DepositQR.d.ts +11 -4
  30. package/build/ui/profile/DepositQR.js +82 -38
  31. package/build/ui/profile/DepositQR.js.map +1 -1
  32. package/build/ui/profile/Payment.js +3 -9
  33. package/build/ui/profile/Payment.js.map +1 -1
  34. package/build/ui/profile/Profile.d.ts +8 -3
  35. package/build/ui/profile/Profile.js +15 -9
  36. package/build/ui/profile/Profile.js.map +1 -1
  37. package/build/ui/router.d.ts +4 -2
  38. package/build/ui/router.js +4 -6
  39. package/build/ui/router.js.map +1 -1
  40. package/build/ui/styles.js +2 -1
  41. package/build/ui/styles.js.map +1 -1
  42. package/build/ui/toast/index.js +2 -0
  43. package/build/ui/toast/index.js.map +1 -1
  44. package/build/ui/uikit/animationts.d.ts +5 -0
  45. package/build/ui/uikit/animationts.js +19 -0
  46. package/build/ui/uikit/animationts.js.map +1 -0
  47. package/build/ui/uikit/badge.d.ts +5 -0
  48. package/build/ui/uikit/badge.js +19 -0
  49. package/build/ui/uikit/badge.js.map +1 -0
  50. package/build/ui/uikit/tabs.d.ts +2 -1
  51. package/build/ui/uikit/tabs.js +31 -17
  52. package/build/ui/uikit/tabs.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/activity.ts +22 -1
  55. package/src/core/defuse.ts +102 -0
  56. package/src/core/exchange.ts +38 -10
  57. package/src/core/pendings.ts +81 -38
  58. package/src/ui/bridge/Bridge.tsx +30 -312
  59. package/src/ui/bridge/SelectSender.tsx +24 -2
  60. package/src/ui/bridge/SelectToken.tsx +15 -6
  61. package/src/ui/bridge/TokenAmountCard.tsx +347 -0
  62. package/src/ui/icons/warning.tsx +1 -1
  63. package/src/ui/profile/DepositFlow.tsx +286 -10
  64. package/src/ui/profile/DepositQR.tsx +196 -76
  65. package/src/ui/profile/Payment.tsx +4 -27
  66. package/src/ui/profile/Profile.tsx +100 -91
  67. package/src/ui/router.tsx +5 -7
  68. package/src/ui/styles.ts +2 -1
  69. package/src/ui/toast/index.tsx +2 -0
  70. package/src/ui/uikit/animationts.ts +20 -0
  71. package/src/ui/uikit/badge.tsx +24 -0
  72. package/src/ui/uikit/tabs.tsx +38 -24
@@ -5,7 +5,6 @@ import uuid4 from "uuid4";
5
5
 
6
6
  import { ArrowRightIcon } from "../icons/arrow-right";
7
7
  import ExchangeIcon from "../icons/exchange";
8
- import RefreshIcon from "../icons/refresh";
9
8
 
10
9
  import { HotKit } from "../../HotKit";
11
10
  import { chains, Network, WalletType } from "../../core/chains";
@@ -16,21 +15,15 @@ import { formatter } from "../../core/utils";
16
15
  import { tokens } from "../../core/tokens";
17
16
  import { Token } from "../../core/token";
18
17
 
19
- import { ActionButton, Button } from "../uikit/button";
20
- import { H5, PLarge, PSmall, PTiny } from "../uikit/text";
18
+ import { useAnimations } from "../uikit/animationts";
19
+ import { H5, PSmall, PTiny } from "../uikit/text";
20
+ import { ActionButton } from "../uikit/button";
21
21
  import { Skeleton } from "../uikit/loader";
22
22
  import { ImageView } from "../uikit/image";
23
23
 
24
24
  import Popup from "../Popup";
25
- import { openConnector, openSelectRecipient, openSelectSender, openSelectTokenPopup } from "../router";
26
25
  import DepositQR from "../profile/DepositQR";
27
- import { TokenIcon } from "./TokenCard";
28
-
29
- const animations = {
30
- success: "https://hex.exchange/success.json",
31
- failed: "https://hex.exchange/error.json",
32
- loading: "https://hex.exchange/loading.json",
33
- };
26
+ import { BadgeButton, Card, CardBody, CardHeader, ChainButton, TokenAmountCard, TokenPreview, Tooltip } from "./TokenAmountCard";
34
27
 
35
28
  export interface ProcessingState {
36
29
  status: "qr" | "processing" | "success" | "error";
@@ -74,13 +67,8 @@ export const Bridge = observer(({ kit, widget, setup, onClose, onProcess, onStat
74
67
  const [isError, setIsError] = useState<string | null>(null);
75
68
  const [isReviewing, setIsReviewing] = useState(false);
76
69
 
77
- useState(() => {
78
- fetch(animations.loading);
79
- fetch(animations.success);
80
- fetch(animations.failed);
81
- });
82
-
83
70
  const [processing, setProcessing] = useState<ProcessingState | null>(null);
71
+ const animations = useAnimations();
84
72
 
85
73
  useEffect(() => {
86
74
  onStateUpdate?.(processing);
@@ -243,14 +231,16 @@ export const Bridge = observer(({ kit, widget, setup, onClose, onProcess, onStat
243
231
  }
244
232
  };
245
233
 
246
- if (processing?.status === "qr") {
234
+ if (processing?.status === "qr" && typeof processing.review.qoute === "object") {
247
235
  return (
248
236
  <Popup widget={widget} onClose={onClose} header={<p>{title}</p>} mobileFullscreen={setup?.mobileFullscreen}>
249
237
  <DepositQR //
250
- kit={kit}
251
- review={processing.review}
238
+ depositAmount={processing.review.qoute.amountInFormatted}
239
+ depositAddress={processing.review.qoute.depositAddress!}
252
240
  onConfirm={() => onProcess(process(processing.review))}
253
241
  onCancel={cancelReview}
242
+ token={from}
243
+ kit={kit}
254
244
  />
255
245
  </Popup>
256
246
  );
@@ -302,9 +292,9 @@ export const Bridge = observer(({ kit, widget, setup, onClose, onProcess, onStat
302
292
  }
303
293
 
304
294
  const button = () => {
305
- if (refundWallet == null) return <ActionButton onClick={() => openConnector(kit)}>Sign in to HEX</ActionButton>;
306
295
  if (sender == null) return <ActionButton disabled>Confirm</ActionButton>;
307
296
  if (recipient == null) return <ActionButton disabled>Confirm</ActionButton>;
297
+ if (refundWallet == null) return <ActionButton onClick={() => kit.router.openConnector(kit)}>Sign in to HEX</ActionButton>;
308
298
  if (sender !== "qr" && +from.float(kit.balance(sender, from)).toFixed(FIXED) < +amountFrom.toFixed(FIXED)) return <ActionButton disabled>Insufficient balance</ActionButton>;
309
299
  return (
310
300
  <ActionButton style={{ width: "100%", marginTop: 40 }} disabled={isReviewing || isError != null} onClick={handleConfirm}>
@@ -316,118 +306,22 @@ export const Bridge = observer(({ kit, widget, setup, onClose, onProcess, onStat
316
306
  return (
317
307
  <Popup widget={widget} onClose={onClose} header={<p>{title}</p>} mobileFullscreen={setup?.mobileFullscreen} style={{ background: "#191919" }}>
318
308
  <div style={{ display: "flex", flexDirection: "column", gap: 4, width: "100%", height: "100%" }}>
319
- <Card style={{ borderRadius: "20px 20px 2px 2px" }}>
320
- <CardHeader>
321
- <ChainButton onClick={() => openSelectTokenPopup({ kit, onSelect: (token, wallet) => (setFrom(token), setSender(wallet)) })}>
322
- <PSmall>From</PSmall>
323
- <ImageView src={chains.get(from.chain)?.logo || ""} alt={from.symbol} size={16} />
324
- <PSmall>{chains.get(from.chain)?.name}</PSmall>
325
- <ArrowRightIcon style={{ marginLeft: -8, transform: "rotate(-270deg)" }} color="#ababab" />
326
- </ChainButton>
327
-
328
- <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
329
- <PSmall>Sender:</PSmall>
330
- <BadgeButton onClick={() => openSelectSender({ kit, type: from.type, onSelect: (sender) => setSender(sender) })}>
331
- <PSmall>{sender == null ? "Select" : sender !== "qr" ? formatter.truncateAddress(sender.address, 8) : "QR"}</PSmall>
332
- <Tooltip id="sender-tooltip">
333
- <PSmall>Select sender wallet</PSmall>
334
- </Tooltip>
335
- </BadgeButton>
336
- </div>
337
- </CardHeader>
338
-
339
- <CardBody>
340
- <div style={{ width: "100%", display: "flex", alignItems: "center", gap: 8, justifyContent: "space-between" }}>
341
- <TokenPreview
342
- token={from}
343
- onSelect={() =>
344
- openSelectTokenPopup({
345
- onSelect: (token, wallet) => (setFrom(token), setSender(wallet)),
346
- initialChain: from.chain,
347
- kit,
348
- })
349
- }
350
- />
351
-
352
- {isReviewing && type === "exactOut" ? (
353
- <Skeleton />
354
- ) : (
355
- <input //
356
- name="from"
357
- type="text"
358
- className="input"
359
- autoComplete="off"
360
- autoCapitalize="off"
361
- autoCorrect="off"
362
- readOnly={setup?.readonlyAmount}
363
- value={isFiat ? `$${showAmountFrom}` : showAmountFrom}
364
- onChange={(e) => (setType("exactIn"), setValue(e.target.value))}
365
- placeholder="0"
366
- autoFocus
367
- />
368
- )}
369
- </div>
370
-
371
- {isFiat && (
372
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
373
- {sender !== "qr" && (
374
- <AvailableBalance>
375
- <PSmall>Balance: ${from.readable(availableBalance, from.usd)}</PSmall>
376
- <Button onClick={() => sender && kit.fetchToken(from, sender)}>
377
- <RefreshIcon color="#fff" />
378
- </Button>
379
- </AvailableBalance>
380
- )}
381
-
382
- {sender === "qr" && <div />}
383
-
384
- <div style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
385
- {from.usd !== 0 && <PSmall style={{ marginRight: 8 }}>{`${from.readable(amountFrom / from.usd)} ${from.symbol}`}</PSmall>}
386
-
387
- {from.usd !== 0 && (
388
- <BadgeButton style={{ border: `1px solid #fff` }} onClick={() => setIsFiat(!isFiat)}>
389
- <PTiny>USD</PTiny>
390
- </BadgeButton>
391
- )}
392
-
393
- {sender !== "qr" && (
394
- <BadgeButton onClick={handleMax}>
395
- <PTiny>MAX</PTiny>
396
- </BadgeButton>
397
- )}
398
- </div>
399
- </div>
400
- )}
401
-
402
- {!isFiat && (
403
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
404
- {sender !== "qr" && (
405
- <AvailableBalance>
406
- <PSmall>Balance: {`${from.readable(availableBalance)} ${from.symbol}`}</PSmall>
407
- <Button style={{ marginTop: 2 }} onClick={() => sender && kit.fetchToken(from, sender)}>
408
- <RefreshIcon color="#fff" />
409
- </Button>
410
- </AvailableBalance>
411
- )}
412
-
413
- {sender === "qr" && <div />}
414
- <div style={{ display: "flex", alignItems: "center", gap: 4 }}>
415
- {from.usd !== 0 && <PSmall style={{ marginRight: 8 }}>${from.readable(amountFrom, from.usd)}</PSmall>}
416
- {from.usd !== 0 && (
417
- <BadgeButton onClick={() => setIsFiat(!isFiat)}>
418
- <PTiny>USD</PTiny>
419
- </BadgeButton>
420
- )}
421
- {sender !== "qr" && (
422
- <BadgeButton onClick={handleMax}>
423
- <PTiny>MAX</PTiny>
424
- </BadgeButton>
425
- )}
426
- </div>
427
- </div>
428
- )}
429
- </CardBody>
430
- </Card>
309
+ <TokenAmountCard
310
+ token={from}
311
+ isFiat={isFiat}
312
+ sender={sender}
313
+ amount={amountFrom}
314
+ readableAmount={String(showAmountFrom)}
315
+ readonlyAmount={setup?.readonlyAmount}
316
+ availableBalance={availableBalance}
317
+ isReviewing={isReviewing && type === "exactOut"}
318
+ setValue={setValue}
319
+ setIsFiat={setIsFiat}
320
+ setSender={setSender}
321
+ handleMax={handleMax}
322
+ setToken={setFrom}
323
+ kit={kit}
324
+ />
431
325
 
432
326
  <div style={{ position: "relative", height: 1, width: "100%" }}>
433
327
  <SwitchButton
@@ -446,7 +340,7 @@ export const Bridge = observer(({ kit, widget, setup, onClose, onProcess, onStat
446
340
 
447
341
  <Card style={{ borderRadius: "2px 2px 20px 20px" }}>
448
342
  <CardHeader>
449
- <ChainButton onClick={() => openSelectTokenPopup({ kit, onSelect: (token, wallet) => (setTo(token), setRecipient(wallet)) })}>
343
+ <ChainButton onClick={() => kit.router.openSelectTokenPopup({ kit, onSelect: (token, wallet) => (setTo(token), setRecipient(wallet)) })}>
450
344
  <PSmall>To</PSmall>
451
345
  <ImageView src={chains.get(to.chain)?.logo || ""} alt={to.symbol} size={16} />
452
346
  <PSmall>{chains.get(to.chain)?.name}</PSmall>
@@ -455,7 +349,7 @@ export const Bridge = observer(({ kit, widget, setup, onClose, onProcess, onStat
455
349
 
456
350
  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
457
351
  <PSmall>Recipient:</PSmall>
458
- <BadgeButton onClick={() => openSelectRecipient({ kit, chain: to.chain, onSelect: (recipient) => setRecipient(recipient) })}>
352
+ <BadgeButton onClick={() => kit.router.openSelectRecipient({ kit, chain: to.chain, onSelect: (recipient) => setRecipient(recipient) })}>
459
353
  <PSmall>{recipient == null ? "Select" : formatter.truncateAddress(recipient.address, 8)}</PSmall>
460
354
  <Tooltip id="recipient-tooltip">
461
355
  <PSmall>Select recipient wallet</PSmall>
@@ -469,7 +363,7 @@ export const Bridge = observer(({ kit, widget, setup, onClose, onProcess, onStat
469
363
  <TokenPreview
470
364
  token={to}
471
365
  onSelect={() =>
472
- openSelectTokenPopup({
366
+ kit.router.openSelectTokenPopup({
473
367
  kit,
474
368
  initialChain: to.chain,
475
369
  onSelect: (token, wallet) => {
@@ -511,16 +405,6 @@ export const Bridge = observer(({ kit, widget, setup, onClose, onProcess, onStat
511
405
  );
512
406
  });
513
407
 
514
- const TokenPreview = ({ style, token, onSelect }: { style?: React.CSSProperties; token: Token; onSelect: (token: Token) => void }) => {
515
- return (
516
- <SelectTokenButton style={style} onClick={() => onSelect(token)}>
517
- <TokenIcon withoutChain token={token} size={32} />
518
- <PLarge>{token.symbol}</PLarge>
519
- <ArrowRightIcon style={{ flexShrink: 0, position: "absolute", right: 4 }} />
520
- </SelectTokenButton>
521
- );
522
- };
523
-
524
408
  const TextField = styled(PTiny)`
525
409
  max-width: 100%;
526
410
  min-width: 300px;
@@ -536,172 +420,6 @@ const TextField = styled(PTiny)`
536
420
  line-break: anywhere;
537
421
  `;
538
422
 
539
- const Tooltip = styled.div`
540
- transition: 0.2s transform, 0.2s opacity;
541
- transform: translateY(8px);
542
- opacity: 0;
543
- position: absolute;
544
- top: -48px;
545
- right: 0;
546
- z-index: 100000000;
547
- border-radius: 16px;
548
- background: var(--surface-white, #fff);
549
- padding: 4px 12px;
550
- justify-content: center;
551
- pointer-events: none;
552
- align-items: center;
553
- gap: 4px;
554
-
555
- p {
556
- white-space: nowrap;
557
- color: #000;
558
- }
559
-
560
- &::after {
561
- content: "";
562
- position: absolute;
563
- top: 100%;
564
- right: 8px;
565
- transform: translateX(-50%);
566
- width: 0;
567
- height: 0;
568
- border-left: 8px solid transparent;
569
- border-right: 8px solid transparent;
570
- border-top: 8px solid #fff;
571
- }
572
- `;
573
-
574
- const BadgeButton = styled.button`
575
- display: flex;
576
- border-radius: 8px;
577
- border: 1px solid #323232;
578
- padding: 4px 8px;
579
- background: transparent;
580
- transition: 0.2s border-color;
581
- position: relative;
582
- cursor: pointer;
583
- outline: none;
584
- gap: 4px;
585
-
586
- &:hover {
587
- border-color: #4e4e4e;
588
- }
589
- `;
590
-
591
- const ChainButton = styled.button`
592
- display: flex;
593
- align-items: center;
594
- padding: 0;
595
- gap: 8px;
596
- flex-shrink: 0;
597
- cursor: pointer;
598
- outline: none;
599
- border: none;
600
- background: transparent;
601
- transition: 0.2s opacity;
602
-
603
- &:hover {
604
- opacity: 0.8;
605
- }
606
- `;
607
-
608
- const SelectTokenButton = styled.button`
609
- display: flex;
610
- align-items: center;
611
- gap: 8px;
612
- flex-shrink: 0;
613
- cursor: pointer;
614
- outline: none;
615
- border: none;
616
- position: relative;
617
- background: transparent;
618
- border-radius: 24px;
619
- padding: 4px;
620
- padding-right: 28px;
621
- margin: -4px;
622
- max-width: 160px;
623
- transition: 0.2s background-color;
624
-
625
- &:hover {
626
- background: rgba(255, 255, 255, 0.2);
627
- }
628
-
629
- p {
630
- overflow: hidden;
631
- text-overflow: ellipsis;
632
- white-space: nowrap;
633
- }
634
- `;
635
-
636
- const AvailableBalance = styled.div`
637
- display: flex;
638
- align-items: center;
639
- overflow: hidden;
640
- max-width: 200px;
641
- white-space: nowrap;
642
- gap: 4px;
643
-
644
- p {
645
- overflow: hidden;
646
- text-overflow: ellipsis;
647
- white-space: nowrap;
648
- }
649
- `;
650
-
651
- const Card = styled.div`
652
- text-align: left;
653
- align-items: flex-start;
654
- justify-content: center;
655
- flex-direction: column;
656
-
657
- display: flex;
658
- width: 100%;
659
-
660
- border-radius: 20px 20px 2px 2px;
661
- border: 1px solid #323232;
662
- background: #1f1f1f;
663
-
664
- input {
665
- outline: none;
666
- border: none;
667
- background: none;
668
- color: #fff;
669
- font-size: 32px;
670
- font-weight: bold;
671
- width: 100%;
672
- line-height: 40px;
673
- text-align: left;
674
- align-items: flex-start;
675
- justify-content: center;
676
- background: transparent;
677
- text-align: right;
678
- border: none;
679
- padding: 0;
680
- margin: 0;
681
- }
682
- `;
683
-
684
- const CardHeader = styled.div`
685
- display: flex;
686
- align-items: center;
687
- justify-content: space-between;
688
- padding: 8px 16px;
689
- width: 100%;
690
- gap: 8px;
691
- `;
692
-
693
- const CardBody = styled.div`
694
- padding: 16px;
695
- width: 100%;
696
- flex-direction: column;
697
- align-items: flex-start;
698
- border-radius: 20px 20px 0 0;
699
- border-top: 1px solid #323232;
700
- background: #272727;
701
- display: flex;
702
- gap: 8px;
703
- `;
704
-
705
423
  const SwitchButton = styled.button`
706
424
  position: absolute;
707
425
  left: 50%;
@@ -13,15 +13,19 @@ import { ConnectorType, OmniConnector } from "../../core/OmniConnector";
13
13
  import { OmniWallet } from "../../core/OmniWallet";
14
14
  import { WalletType } from "../../core/chains";
15
15
  import { formatter } from "../../core/utils";
16
+ import { PMedium, PSmall } from "../uikit/text";
17
+ import { WalletPicker } from "../connect/WalletPicker";
18
+ import { QRAnimation } from "../profile/DepositQR";
16
19
 
17
20
  interface SelectSenderProps {
18
21
  type: WalletType;
19
22
  kit: HotKit;
23
+ disableQR?: boolean;
20
24
  onClose: () => void;
21
25
  onSelect: (wallet?: OmniWallet | "qr") => void;
22
26
  }
23
27
 
24
- export const SelectSender = observer(({ kit, type, onSelect, onClose }: SelectSenderProps) => {
28
+ export const SelectSender = observer(({ kit, type, disableQR, onSelect, onClose }: SelectSenderProps) => {
25
29
  const connectors = kit.connectors.filter((t) => t.walletTypes.includes(type) && t.type !== ConnectorType.SOCIAL);
26
30
  const noExternal = type === WalletType.OMNI || type === WalletType.COSMOS;
27
31
 
@@ -31,9 +35,27 @@ export const SelectSender = observer(({ kit, type, onSelect, onClose }: SelectSe
31
35
  onClose();
32
36
  };
33
37
 
38
+ if (connectors.length === 0 && (noExternal || disableQR)) {
39
+ return (
40
+ <Popup onClose={onClose} header={<p>Select sender</p>}>
41
+ <div style={{ width: "100%", height: 200, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column", gap: 12 }}>
42
+ <PSmall>
43
+ No compatible wallets found,
44
+ <br />
45
+ try using flow for external wallets
46
+ </PSmall>
47
+ </div>
48
+ </Popup>
49
+ );
50
+ }
51
+
52
+ if (connectors.length === 1 && (noExternal || disableQR)) {
53
+ return <WalletPicker initialConnector={connectors[0]} onSelect={onSelect} onClose={onClose} />;
54
+ }
55
+
34
56
  return (
35
57
  <Popup header={<p>Select sender</p>} onClose={onClose}>
36
- {!noExternal && (
58
+ {!noExternal && !disableQR && (
37
59
  <PopupOption onClick={() => (onSelect("qr"), onClose())}>
38
60
  <div style={{ width: 44, height: 44, borderRadius: 16, background: "#000", display: "flex", alignItems: "center", justifyContent: "center" }}>
39
61
  <QRIcon />
@@ -17,18 +17,27 @@ import { TokenCard } from "./TokenCard";
17
17
 
18
18
  interface SelectTokenPopupProps {
19
19
  kit: HotKit;
20
+ disableChains?: number[];
20
21
  initialChain?: number;
21
22
  onClose: () => void;
22
23
  onSelect: (token: Token, wallet?: OmniWallet) => void;
23
24
  }
24
25
 
25
- export const SelectTokenPopup = observer(({ kit, initialChain, onClose, onSelect }: SelectTokenPopupProps) => {
26
+ export const SelectTokenPopup = observer(({ kit, disableChains, initialChain, onClose, onSelect }: SelectTokenPopupProps) => {
26
27
  const [chain, setChain] = useState<number | null>(initialChain || null);
27
28
  const [search, setSearch] = useState<string>("");
28
29
 
30
+ const availableTokens = tokens.list.filter((token) => !disableChains || !disableChains.includes(token.chain));
31
+ const selectChain = (chain: number) => {
32
+ setChain(chain);
33
+ setSearch("");
34
+ const tokens = availableTokens.filter((t) => t.chain === chain);
35
+ if (tokens.length === 1) onSelect(tokens[0]);
36
+ };
37
+
29
38
  if (chain == null) {
30
39
  const chains: Record<number, { chain: number; balance: number; name: string; icon: string }> = {};
31
- tokens.list.forEach((token) => {
40
+ availableTokens.forEach((token) => {
32
41
  if (!chains[token.chain])
33
42
  chains[token.chain] = {
34
43
  chain: token.chain,
@@ -56,7 +65,7 @@ export const SelectTokenPopup = observer(({ kit, initialChain, onClose, onSelect
56
65
  if (search && !name.toLowerCase().includes(search.toLowerCase())) return;
57
66
 
58
67
  return (
59
- <PopupOption onClick={() => (setChain(chain), setSearch(""))}>
68
+ <PopupOption onClick={() => selectChain(chain)}>
60
69
  <ImageView src={icon} alt={name} size={24} />
61
70
  <p style={{ fontSize: 24, fontWeight: "bold" }}>{name}</p>
62
71
  {balance > 0 && <p style={{ marginLeft: "auto", fontSize: 20, color: "#c6c6c6" }}>${formatter.amount(balance)}</p>}
@@ -67,12 +76,12 @@ export const SelectTokenPopup = observer(({ kit, initialChain, onClose, onSelect
67
76
  );
68
77
  }
69
78
 
70
- if (chain !== -4) {
79
+ if (chain !== Network.Omni && chain !== Network.HotCraft) {
71
80
  return (
72
81
  <Popup onClose={onClose} header={<p>Select token</p>} style={{ minHeight: 300 }}>
73
82
  <SearchInput type="text" placeholder="Search token" onChange={(e) => setSearch(e.target.value)} />
74
83
 
75
- {tokens.list
84
+ {availableTokens
76
85
  .filter((token) => token.chain === chain && token.symbol.toLowerCase().includes(search.toLowerCase()))
77
86
  .sort((a, b) => {
78
87
  const wallet = kit.wallets.find((w) => w.type === a.type)!;
@@ -95,7 +104,7 @@ export const SelectTokenPopup = observer(({ kit, initialChain, onClose, onSelect
95
104
  <SearchInput type="text" placeholder="Search token" onChange={(e) => setSearch(e.target.value)} />
96
105
  {kit.walletsTokens
97
106
  .filter(({ token, balance }) => {
98
- if (token.chain !== Network.Omni) return false;
107
+ if (token.chain !== chain) return false;
99
108
  if (token.float(balance) < 0.0001) return false;
100
109
  if (!token.symbol.toLowerCase().includes(search.toLowerCase())) return false;
101
110
  used.add(token.address);