@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
@@ -3,107 +3,215 @@ import QRCodeStyling from "qr-code-styling";
3
3
  import { observer } from "mobx-react-lite";
4
4
  import styled from "styled-components";
5
5
 
6
- import { HotKit } from "../../HotKit";
7
- import { BridgeReview } from "../../core/exchange";
8
6
  import { WarningIcon } from "../icons/warning";
7
+ import CopyIcon from "../icons/copy";
9
8
 
9
+ import { HotKit } from "../../HotKit";
10
10
  import { ActionButton, Button } from "../uikit/button";
11
- import { PMedium, PSmall } from "../uikit/text";
12
- import CopyIcon from "../icons/copy";
11
+ import { PLarge, PMedium, PSmall, PTiny } from "../uikit/text";
12
+ import { Token } from "../../core/token";
13
+ import { WarningBox } from "../uikit/badge";
14
+ import uuid4 from "uuid4";
13
15
 
14
- const DepositQR = observer(({ kit, review, onConfirm, onCancel }: { kit: HotKit; review: BridgeReview; onConfirm: () => void; onCancel?: () => void }) => {
16
+ export const QRAnimation = ({ size = 180 }: { size?: number }) => {
15
17
  const qrCodeRef = useRef<HTMLDivElement>(null);
16
18
  const [qrCode] = useState<QRCodeStyling | null>(() => {
17
- if (review.qoute === "deposit" || review.qoute === "withdraw") return null;
18
19
  return new QRCodeStyling({
19
- data: review.qoute.depositAddress,
20
- dotsOptions: { color: "#eeeeee", type: "dots" },
20
+ data: uuid4().slice(0, 6),
21
+ dotsOptions: { color: "#eeeeee73", type: "dots" },
21
22
  backgroundOptions: { color: "transparent" },
22
23
  shape: "square",
23
- width: 180,
24
- height: 180,
24
+ width: window.innerWidth < 760 ? size * 0.7 : size,
25
+ height: window.innerWidth < 760 ? size * 0.7 : size,
25
26
  type: "svg",
26
27
  });
27
28
  });
28
29
 
29
30
  useEffect(() => {
30
31
  if (!qrCodeRef.current) return;
31
- if (review.qoute === "deposit" || review.qoute === "withdraw") return;
32
32
  qrCode?.append(qrCodeRef.current);
33
+
34
+ const interval = setInterval(() => {
35
+ qrCode?.update({ data: uuid4().slice(0, 6) });
36
+ }, 600);
37
+
38
+ return () => clearInterval(interval);
33
39
  }, []);
34
40
 
35
- if (review.qoute === "deposit" || review.qoute === "withdraw") return null;
36
- const depositAddress = review.qoute.depositAddress as string;
37
-
38
- const handleCopy = async () => {
39
- try {
40
- await navigator.clipboard.writeText(depositAddress);
41
- kit.toast.success("Address copied to clipboard");
42
- } catch (error) {
43
- kit.toast.failed("Failed to copy address");
44
- }
45
- };
46
-
47
- return (
48
- <div style={{ position: "relative", width: "100%", height: "100%", gap: 8, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", flex: 1 }}>
49
- {onCancel != null && (
50
- <CloseButton onClick={onCancel}>
51
- <PSmall>Back</PSmall>
52
- </CloseButton>
53
- )}
54
-
55
- <div ref={qrCodeRef} style={{ marginTop: "auto", borderRadius: 12, padding: "4px 4px 0 4px", border: "1px solid #2d2d2d", background: "#1c1c1c", textAlign: "left" }}></div>
56
-
57
- <PMedium style={{ textAlign: "center", marginTop: 16, color: "#ababab", width: "100%" }}>
58
- Send <Pre>{review.qoute.amountInFormatted}</Pre> <Pre>{review.from.symbol}</Pre> on <Pre>{review.from.chainName}</Pre> chain to:
59
- </PMedium>
60
-
61
- <div style={{ width: "100%", justifyContent: "center", display: "flex", gap: 4 }}>
62
- <Pre style={{ fontSize: 14, fontWeight: "bold", padding: 0, background: "transparent", border: "none" }}>{depositAddress}</Pre>
63
- <Button onClick={handleCopy}>
64
- <CopyIcon width={16} height={16} color="#ababab" />
65
- </Button>
41
+ return <div ref={qrCodeRef} style={{ borderRadius: 12, padding: "4px 4px 0 4px", border: "1px solid #2d2d2d", background: "#1c1c1c" }}></div>;
42
+ };
43
+
44
+ const DepositQR = observer(
45
+ ({
46
+ kit,
47
+ token,
48
+ depositAmount,
49
+ minimumAmount,
50
+ depositAddress,
51
+ memo,
52
+ onConfirm,
53
+ onCancel,
54
+ }: {
55
+ kit: HotKit;
56
+ token: Token;
57
+ memo?: string;
58
+ depositAmount?: string;
59
+ minimumAmount?: number;
60
+ depositAddress: string;
61
+ onConfirm: () => void;
62
+ onCancel?: () => void;
63
+ }) => {
64
+ const qrCodeRef = useRef<HTMLDivElement>(null);
65
+ const [qrCode] = useState<QRCodeStyling | null>(() => {
66
+ return new QRCodeStyling({
67
+ data: depositAddress,
68
+ dotsOptions: { color: "#eeeeee", type: "dots" },
69
+ backgroundOptions: { color: "transparent" },
70
+ shape: "square",
71
+ width: 140,
72
+ height: 140,
73
+ type: "svg",
74
+ });
75
+ });
76
+
77
+ useEffect(() => {
78
+ if (!qrCodeRef.current) return;
79
+ qrCode?.append(qrCodeRef.current);
80
+ }, []);
81
+
82
+ const handleCopy = async (value: string, label?: string) => {
83
+ try {
84
+ await navigator.clipboard.writeText(value);
85
+ kit.toast.success(label != null ? `${label} copied to clipboard` : "Value copied to clipboard");
86
+ } catch (error) {
87
+ kit.toast.failed(label != null ? `Failed to copy ${label}` : "Failed to copy value");
88
+ }
89
+ };
90
+
91
+ return (
92
+ <div style={{ position: "relative", width: "100%", height: "100%", gap: 4, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", flex: 1 }}>
93
+ {onCancel != null && (
94
+ <div style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center", height: 32 }}>
95
+ <CloseButton onClick={onCancel}>
96
+ <PSmall>Back</PSmall>
97
+ </CloseButton>
98
+ <PLarge>Exchange via QR</PLarge>
99
+ </div>
100
+ )}
101
+
102
+ <div style={{ width: "100%", display: "flex", gap: 4 }}>
103
+ <div>
104
+ <QRContainer ref={qrCodeRef} />
105
+ </div>
106
+
107
+ <Card>
108
+ <Row style={{ background: "#1c1c1c", flexDirection: "column", textAlign: "left", alignItems: "flex-start" }}>
109
+ <PSmall style={{ color: "#d4d4d4" }}>Deposit address</PSmall>
110
+ <PSmall style={{ marginTop: 4, fontWeight: 600, fontFamily: "monospace", textAlign: "left" }}>
111
+ {depositAddress}
112
+ <Button style={{ marginLeft: 4, display: "inline-block", verticalAlign: "bottom", flexShrink: 0, width: 20, height: 20 }} onClick={() => handleCopy(depositAddress, "Address")}>
113
+ <CopyIcon width={20} height={20} color="#ababab" />
114
+ </Button>
115
+ </PSmall>
116
+ </Row>
117
+
118
+ {minimumAmount != null && (
119
+ <Row>
120
+ <PSmall>Minimum deposit</PSmall>
121
+ <PMedium>
122
+ {token.readable(minimumAmount)} {token.symbol}
123
+ </PMedium>
124
+ </Row>
125
+ )}
126
+
127
+ {depositAmount != null && (
128
+ <>
129
+ <Row>
130
+ <PSmall>Network</PSmall>
131
+ <PMedium>{token.chainName}</PMedium>
132
+ </Row>
133
+
134
+ <Row>
135
+ <PSmall>Token</PSmall>
136
+ <PMedium>{token.symbol}</PMedium>
137
+ </Row>
138
+
139
+ <Row>
140
+ <PSmall>Required transfer</PSmall>
141
+ <PMedium>
142
+ {depositAmount}
143
+ <Button style={{ marginLeft: 4, display: "inline-block", verticalAlign: "bottom", flexShrink: 0, width: 20, height: 20 }} onClick={() => handleCopy(depositAmount, "Amount")}>
144
+ <CopyIcon width={20} height={20} color="#ababab" />
145
+ </Button>
146
+ </PMedium>
147
+ </Row>
148
+ </>
149
+ )}
150
+
151
+ {memo != null && (
152
+ <Row>
153
+ <PSmall style={{ fontWeight: 600 }}>Required memo</PSmall>
154
+ <div style={{ display: "flex", gap: 4, alignItems: "center" }}>
155
+ <PMedium style={{ fontWeight: 600, color: "#f3ae47" }}>{memo}</PMedium>
156
+ <Button style={{ flexShrink: 0, marginTop: 2 }} onClick={() => handleCopy(memo, "Memo")}>
157
+ <CopyIcon width={20} height={20} color="#ababab" />
158
+ </Button>
159
+ </div>
160
+ </Row>
161
+ )}
162
+ </Card>
163
+ </div>
164
+
165
+ <WarningBox type="warning" style={{ marginTop: "auto" }}>
166
+ Only deposit {token.symbol} from {token.chainName} network{memo != null ? ` with memo "${memo}"` : ""}, otherwise funds will be lost!
167
+ </WarningBox>
168
+
169
+ <ActionButton style={{ marginTop: 8 }} onClick={onConfirm}>
170
+ I sent the funds
171
+ </ActionButton>
66
172
  </div>
173
+ );
174
+ }
175
+ );
67
176
 
68
- <WarningBadge>
69
- <WarningIcon color="#F3AE47" style={{ marginTop: 4, flexShrink: 0 }} />
70
- <PSmall style={{ color: "#F3AE47", fontWeight: "bold" }}>
71
- Only deposit {review.from.symbol} from {review.from.chainName} network.
72
- <br />
73
- Depositing other assets or using a different network will result in loss of funds
74
- </PSmall>
75
- </WarningBadge>
76
-
77
- <ActionButton style={{ marginTop: 12 }} onClick={onConfirm}>
78
- I sent the funds
79
- </ActionButton>
80
- </div>
81
- );
82
- });
83
-
84
- const WarningBadge = styled.div`
177
+ const Card = styled.div`
85
178
  border-radius: 8px;
86
- border: 1px solid var(--border-border-orange, #f3ae47);
87
- background: var(--surface-warning, #3f311d);
88
- padding: 8px;
179
+ border: 1px solid #323232;
180
+ background: #1f1f1f;
181
+ overflow: hidden;
182
+ height: fit-content;
183
+
184
+ width: 100%;
89
185
  display: flex;
90
- gap: 8px;
91
- text-align: left;
186
+ flex-direction: column;
92
187
  margin-top: 12px;
188
+
189
+ p {
190
+ text-align: left;
191
+ word-break: break-all;
192
+ white-space: pre-wrap;
193
+ word-wrap: break-word;
194
+ overflow-wrap: break-word;
195
+ color: #fff;
196
+ }
93
197
  `;
94
198
 
95
- const Pre = styled.code`
96
- display: inline;
97
- background: #2d2d2d;
98
- padding: 0 2px;
99
- border-radius: 4px;
100
- border: 1px solid #ffffff14;
101
- word-break: break-all;
102
- white-space: pre-wrap;
103
- word-wrap: break-word;
104
- overflow-wrap: break-word;
105
- text-align: left;
106
- margin: 0;
199
+ const Row = styled.div`
200
+ padding: 8px 12px;
201
+ width: 100%;
202
+ display: flex;
203
+ align-items: center;
204
+ justify-content: space-between;
205
+ flex-wrap: wrap;
206
+ position: relative;
207
+
208
+ > *:first-child {
209
+ margin-right: 12px;
210
+ }
211
+
212
+ & + & {
213
+ border-top: 1px solid #323232;
214
+ }
107
215
  `;
108
216
 
109
217
  const CloseButton = styled(Button)`
@@ -122,4 +230,16 @@ const CloseButton = styled(Button)`
122
230
  background: #2d2d2d;
123
231
  `;
124
232
 
233
+ const QRContainer = styled.div`
234
+ margin-top: 12px;
235
+ border-radius: 12px;
236
+ border: 1px solid #2d2d2d;
237
+ background: #1c1c1c;
238
+ text-align: left;
239
+
240
+ @media (max-width: 760px) {
241
+ display: none;
242
+ }
243
+ `;
244
+
125
245
  export default DepositQR;
@@ -22,7 +22,6 @@ import { HotKit } from "../../HotKit";
22
22
  import { PopupOption, PopupOptionInfo } from "../styles";
23
23
  import { TokenCard } from "../bridge/TokenCard";
24
24
  import Popup from "../Popup";
25
- import DepositQR from "./DepositQR";
26
25
 
27
26
  interface PaymentProps {
28
27
  onReject: (message: string) => void;
@@ -63,7 +62,7 @@ export const Payment = observer(({ kit, intents, title = "Payment", allowedToken
63
62
 
64
63
  const [flow, setFlow] = useState<{
65
64
  token?: Token;
66
- wallet?: OmniWallet | "qr";
65
+ wallet?: OmniWallet;
67
66
  commitment?: Commitment;
68
67
  review?: BridgeReview;
69
68
  success?: { depositQoute?: BridgeReview; processing?: () => Promise<BridgeReview> };
@@ -75,7 +74,7 @@ export const Payment = observer(({ kit, intents, title = "Payment", allowedToken
75
74
  const paymentTitle = title || `Pay ${payableToken.readable(needAmount)} ${payableToken.symbol}`;
76
75
  const showPrepaidToken = payableToken.float(prepaidAmount) >= 0.001;
77
76
 
78
- const selectToken = async (from: Token, wallet?: OmniWallet | "qr") => {
77
+ const selectToken = async (from: Token, wallet?: OmniWallet) => {
79
78
  if (!wallet) return;
80
79
 
81
80
  setFlow({ token: from, wallet, review: undefined, step: "sign" });
@@ -85,7 +84,7 @@ export const Payment = observer(({ kit, intents, title = "Payment", allowedToken
85
84
  const isStable = isStableFrom && isStableTo;
86
85
 
87
86
  let tasks: Promise<BridgeReview>[] = [];
88
- if (isStable && !isDirectDeposit && wallet !== "qr") {
87
+ if (isStable && !isDirectDeposit) {
89
88
  const slippages = [0.0005, 0.001, 0.0015];
90
89
  tasks = slippages.map((slippage) => {
91
90
  const extra = (needAmount * BigInt(Math.floor(slippage * 1000))) / BigInt(1000);
@@ -105,7 +104,7 @@ export const Payment = observer(({ kit, intents, title = "Payment", allowedToken
105
104
  const exectOutReview = await kit.exchange
106
105
  .reviewSwap({
107
106
  slippage: isStable ? STABLE_SLIPPAGE : PAY_SLIPPAGE,
108
- refund: wallet === "qr" ? kit.priorityWallet : wallet,
107
+ refund: wallet,
109
108
  recipient: intents.signer!,
110
109
  amount: needAmount,
111
110
  sender: wallet,
@@ -214,15 +213,6 @@ export const Payment = observer(({ kit, intents, title = "Payment", allowedToken
214
213
  }
215
214
 
216
215
  if (flow?.step === "transfer") {
217
- if (flow.wallet === "qr") {
218
- return (
219
- <Popup onClose={() => onReject("closed")} header={<p>{paymentTitle}</p>}>
220
- <HorizontalStepper steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={2} />
221
- <DepositQR kit={kit} review={flow.review!} onConfirm={confirmPaymentStep} />
222
- </Popup>
223
- );
224
- }
225
-
226
216
  return (
227
217
  <Popup onClose={() => onReject("closed")} header={<p>{paymentTitle}</p>}>
228
218
  <HorizontalStepper style={{ marginBottom: 24 }} steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={2} />
@@ -371,19 +361,6 @@ export const Payment = observer(({ kit, intents, title = "Payment", allowedToken
371
361
  {recommendedTokens.map(({ token, wallet, balance }) => renderToken(token, wallet, balance))}
372
362
  {otherTokens.map(({ token, wallet, balance }) => renderToken(token, wallet, balance))}
373
363
 
374
- {kit.connectors.every((t) => !t.walletTypes.includes(payableToken.originalChain)) && (
375
- <PopupOption style={{ marginTop: 8 }} onClick={() => selectToken(tokens.get(payableToken.originalAddress, payableToken.originalChain), "qr")}>
376
- <div style={{ width: 44, height: 44, borderRadius: 16, background: "#000", display: "flex", alignItems: "center", justifyContent: "center" }}>
377
- <QRIcon />
378
- </div>
379
-
380
- <PopupOptionInfo>
381
- <p>Send via QR code</p>
382
- <span className="wallet-address">Transfer from CEX or external wallet</span>
383
- </PopupOptionInfo>
384
- </PopupOption>
385
- )}
386
-
387
364
  <PopupOption style={{ marginTop: 8 }} onClick={() => kit.router.openConnector(kit)}>
388
365
  <div style={{ width: 44, height: 44, borderRadius: 16, background: "#000", display: "flex", alignItems: "center", justifyContent: "center" }}>
389
366
  <WalletIcon />
@@ -1,6 +1,6 @@
1
1
  import { observer } from "mobx-react-lite";
2
2
  import styled from "styled-components";
3
- import { useEffect } from "react";
3
+ import { useEffect, useState } from "react";
4
4
 
5
5
  import PlusIcon from "../icons/plus";
6
6
  import { LogoutIcon } from "../icons/logout";
@@ -21,10 +21,18 @@ import { HotKit } from "../../HotKit";
21
21
  import { openBridge, openConnector } from "../router";
22
22
  import { TokenCard, TokenIcon } from "../bridge/TokenCard";
23
23
  import Popup from "../Popup";
24
+ import SegmentedControl from "../uikit/tabs";
24
25
 
25
- export const Profile = observer(({ kit, onClose }: { kit: HotKit; onClose: (wallet?: OmniWallet) => void }) => {
26
- let totalBalance = 0;
26
+ interface ProfileProps {
27
+ kit: HotKit;
28
+ widget?: boolean;
29
+ onClose?: (wallet?: OmniWallet) => void;
30
+ onDeposit?: () => void;
31
+ onExchange?: () => void;
32
+ }
27
33
 
34
+ export const Profile = observer(({ kit, widget, onClose, onExchange, onDeposit }: ProfileProps) => {
35
+ let totalBalance = 0;
28
36
  const tokensList = kit.walletsTokens
29
37
  .map(({ token, wallet, balance }) => {
30
38
  if (token.float(balance) < 0.000001) return null;
@@ -52,106 +60,107 @@ export const Profile = observer(({ kit, onClose }: { kit: HotKit; onClose: (wall
52
60
  const socialConnector = kit.connectors.find((connector) => connector.type === ConnectorType.SOCIAL && connector.wallets.length > 0);
53
61
  const connectors = kit.connectors.filter((connector) => connector.type !== ConnectorType.HOTCRAFT);
54
62
 
63
+ const [selectedTab, setSelectedTab] = useState<"pendings" | "withdraw" | "portfolio">("portfolio");
64
+
55
65
  useEffect(() => {
56
66
  if (kit.wallets.length > 0) return;
57
- onClose();
67
+ onClose?.();
58
68
  }, [kit.wallets.length]);
59
69
 
60
70
  return (
61
- <Popup onClose={onClose} style={{ gap: 16 }}>
62
- <div style={{ display: "flex", flexWrap: "wrap", width: "100%", gap: 8 }}>
63
- {connectors.flatMap((connector) => {
64
- return connector.wallets.map((wallet) => (
65
- <WalletCard key={wallet.type} onClick={() => connector.disconnect()}>
66
- <ImageView src={connector.icon} alt={connector.name} size={20} />
67
- {connector.icon !== wallet.icon && <ImageView style={{ position: "absolute", bottom: 4, left: 20 }} src={wallet.icon} alt={connector.name} size={12} />}
68
- <div>{formatter.truncateAddress(wallet.address, 8)}</div>
69
- <LogoutIcon />
70
- </WalletCard>
71
- ));
72
- })}
73
-
74
- {connectors.some((t) => t.wallets.length === 0) && (
75
- <WalletCard
76
- style={{ paddingRight: 12 }}
77
- onClick={() =>
78
- openConnector(kit)
79
- .then((wallet) => onClose(wallet))
80
- .catch(() => onClose())
81
- }
82
- >
83
- <PlusIcon />
84
- Add wallet
85
- </WalletCard>
86
- )}
87
- </div>
71
+ <Popup onClose={onClose} style={{ gap: 16 }} widget={widget}>
72
+ <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 12 }}>
73
+ <div style={{ display: "flex", flexWrap: "wrap", width: "100%", gap: 8 }}>
74
+ {connectors.flatMap((connector) => {
75
+ return connector.wallets.map((wallet) => (
76
+ <WalletCard key={wallet.type} onClick={() => connector.disconnect()}>
77
+ <ImageView src={connector.icon} alt={connector.name} size={20} />
78
+ {connector.icon !== wallet.icon && <ImageView style={{ position: "absolute", bottom: 4, left: 20 }} src={wallet.icon} alt={connector.name} size={12} />}
79
+ <div>{formatter.truncateAddress(wallet.address, 8)}</div>
80
+ <LogoutIcon />
81
+ </WalletCard>
82
+ ));
83
+ })}
88
84
 
89
- <Card>
90
- <PSmall>YOUR BALANCE</PSmall>
91
- <BalanceCard>${formatter.amount(totalBalance)}</BalanceCard>
85
+ {connectors.some((t) => t.wallets.length === 0) && (
86
+ <WalletCard
87
+ style={{ paddingRight: 12 }}
88
+ onClick={() =>
89
+ openConnector(kit)
90
+ .then((wallet) => onClose?.(wallet))
91
+ .catch(() => onClose?.())
92
+ }
93
+ >
94
+ <PlusIcon />
95
+ Add wallet
96
+ </WalletCard>
97
+ )}
98
+ </div>
92
99
 
93
- <div style={{ width: "100%", display: "flex", gap: 12, marginTop: 12, flexWrap: "wrap" }}>
94
- <ActionButton onClick={() => (onClose(), openBridge(kit, { title: "Exchange" }))}>
95
- <ExchangeIcon />
96
- Exchange
97
- </ActionButton>
100
+ <Card>
101
+ <PSmall>YOUR BALANCE</PSmall>
102
+ <BalanceCard>${formatter.amount(totalBalance)}</BalanceCard>
98
103
 
99
- {socialConnector != null && (
100
- <ActionButton onClick={() => socialConnector.openWallet()}>
101
- <ImageView src={socialConnector.icon} alt={socialConnector.name} size={20} />
102
- Open wallet
104
+ <div style={{ width: "100%", display: "flex", gap: 12, marginTop: 12, flexWrap: "wrap" }}>
105
+ <ActionButton onClick={() => (onClose?.(), onExchange ? onExchange() : openBridge(kit, { title: "Exchange" }))}>
106
+ <ExchangeIcon />
107
+ Exchange
103
108
  </ActionButton>
104
- )}
105
109
 
106
- <ActionButton disabled onClick={() => (onClose(), openBridge(kit, { title: "Deposit" }))}>
107
- Deposit
108
- </ActionButton>
109
- </div>
110
- </Card>
111
-
112
- {kit.activity.activityList.length > 0 && (
113
- <TokenCards>
114
- <PSmall style={{ fontSize: 16, fontWeight: 600, color: "#d2d2d2", textAlign: "left" }}>Pendings</PSmall>
115
- {kit.activity.activityList.map((activity) => {
116
- return (
117
- <Card key={activity.id} onClick={() => activity.action()} style={{ flexDirection: "row", gap: 12 }}>
118
- {activity.preview instanceof Token && <TokenIcon token={activity.preview} />}
119
-
120
- <div>
121
- <PMedium style={{ textAlign: "left" }}>{activity.title}</PMedium>
122
- <PSmall style={{ textAlign: "left" }}>{activity.subtitle}</PSmall>
123
- </div>
124
-
125
- {activity.status === "pending" && (
126
- <div style={{ marginLeft: "auto", width: 40, height: 40, display: "flex", alignItems: "center", justifyContent: "center" }}>
127
- <Loader />
110
+ {socialConnector != null && (
111
+ <ActionButton onClick={() => socialConnector.openWallet()}>
112
+ <ImageView src={socialConnector.icon} alt={socialConnector.name} size={20} />
113
+ Open wallet
114
+ </ActionButton>
115
+ )}
116
+
117
+ <ActionButton onClick={() => (onClose?.(), onDeposit ? onDeposit() : kit.router.openDepositFlow(kit))}>Deposit</ActionButton>
118
+ </div>
119
+ </Card>
120
+
121
+ <SegmentedControl
122
+ value={selectedTab}
123
+ onChange={(value) => setSelectedTab(value as "pendings" | "withdraw" | "portfolio")}
124
+ options={[
125
+ { label: "Portfolio", value: "portfolio", background: "#141414", badge: nonOmniTokens.length.toString() },
126
+ { label: "HEX Balance", value: "withdraw", background: "#141414", badge: omniTokens.length.toString() },
127
+ { label: "Activity", value: "pendings", background: "#141414", badge: kit.activity.activityList.length.toString() },
128
+ ]}
129
+ />
130
+
131
+ {selectedTab === "pendings" && (
132
+ <TokenCards>
133
+ {kit.activity.activityList.map((activity) => {
134
+ return (
135
+ <Card key={activity.id} onClick={() => activity.action()} style={{ flexDirection: "row", gap: 12 }}>
136
+ {activity.preview instanceof Token && <TokenIcon token={activity.preview} />}
137
+
138
+ <div>
139
+ <PMedium style={{ textAlign: "left" }}>{activity.title}</PMedium>
140
+ <PSmall style={{ textAlign: "left" }}>{activity.subtitle}</PSmall>
128
141
  </div>
129
- )}
130
142
 
131
- {activity.actionText && !activity.actionLoading && (
132
- <div style={{ marginLeft: "auto", padding: "8px 12px", borderRadius: 16, background: "#1a1a1a", color: "#fff" }}>
133
- <PSmall style={{ color: "#d6d6d6" }}>{activity.actionText}</PSmall>
134
- </div>
135
- )}
136
- </Card>
137
- );
138
- })}
139
- </TokenCards>
140
- )}
141
-
142
- {omniTokens.length > 0 && (
143
- <TokenCards>
144
- <PSmall style={{ fontSize: 16, fontWeight: 600, color: "#d2d2d2", textAlign: "left" }}>Tokens to withdraw</PSmall>
145
- {omniTokens.map((t) => t.component)}
146
- </TokenCards>
147
- )}
148
-
149
- {nonOmniTokens.length > 0 && (
150
- <TokenCards>
151
- <PSmall style={{ fontSize: 16, fontWeight: 600, color: "#d2d2d2", textAlign: "left" }}>Portfolio</PSmall>
152
- {nonOmniTokens.map((t) => t.component)}
153
- </TokenCards>
154
- )}
143
+ {activity.status === "pending" && (
144
+ <div style={{ marginLeft: "auto", width: 40, height: 40, display: "flex", alignItems: "center", justifyContent: "center" }}>
145
+ <Loader />
146
+ </div>
147
+ )}
148
+
149
+ {activity.actionText && !activity.actionLoading && (
150
+ <div style={{ marginLeft: "auto", padding: "8px 12px", borderRadius: 16, background: "#1a1a1a", color: "#fff" }}>
151
+ <PSmall style={{ color: "#d6d6d6" }}>{activity.actionText}</PSmall>
152
+ </div>
153
+ )}
154
+ </Card>
155
+ );
156
+ })}
157
+ </TokenCards>
158
+ )}
159
+
160
+ {selectedTab === "withdraw" && <TokenCards>{omniTokens.map((t) => t.component)}</TokenCards>}
161
+
162
+ {selectedTab === "portfolio" && <TokenCards>{nonOmniTokens.map((t) => t.component)}</TokenCards>}
163
+ </div>
155
164
  </Popup>
156
165
  );
157
166
  });
package/src/ui/router.tsx CHANGED
@@ -132,10 +132,8 @@ export const openConnector = async (kit: HotKit) => {
132
132
  });
133
133
  };
134
134
 
135
- export const openDeposit = (kit: HotKit) => {
136
- return new Promise<void>((resolve, reject) => {
137
- present((close) => <DepositFlow kit={kit} onClose={() => (close(), resolve())} />);
138
- });
135
+ export const openDepositFlow = (kit: HotKit, token?: Token) => {
136
+ present((close) => <DepositFlow kit={kit} initialToken={token} onClose={close} />);
139
137
  };
140
138
 
141
139
  export const openConnectPrimaryWallet = (kit: HotKit) => {
@@ -148,8 +146,8 @@ export const openProfile = (kit: HotKit) => {
148
146
  present((close) => <Profile kit={kit} onClose={close} />);
149
147
  };
150
148
 
151
- export const openSelectTokenPopup = ({ kit, initialChain, onSelect }: { kit: HotKit; initialChain?: number; onSelect: (token: Token, wallet?: OmniWallet) => void }) => {
152
- present((close) => <SelectTokenPopup kit={kit} initialChain={initialChain} onClose={close} onSelect={(t, w) => (onSelect(t, w), close())} />);
149
+ export const openSelectTokenPopup = ({ kit, disableChains, initialChain, onSelect }: { kit: HotKit; disableChains?: number[]; initialChain?: number; onSelect: (token: Token, wallet?: OmniWallet) => void }) => {
150
+ present((close) => <SelectTokenPopup kit={kit} disableChains={disableChains} initialChain={initialChain} onClose={close} onSelect={(t, w) => (onSelect(t, w), close())} />);
153
151
  };
154
152
 
155
153
  export const openWalletPicker = (connector: OmniConnector, onSelect?: (wallet: OmniWallet) => void) => {
@@ -164,7 +162,7 @@ export const openWalletPicker = (connector: OmniConnector, onSelect?: (wallet: O
164
162
  });
165
163
  };
166
164
 
167
- export const openSelectSender = (props: { kit: HotKit; type: WalletType; onSelect: (wallet?: OmniWallet | "qr") => void }) => {
165
+ export const openSelectSender = (props: { kit: HotKit; type: WalletType; disableQR?: boolean; onSelect: (wallet?: OmniWallet | "qr") => void }) => {
168
166
  present((close) => <SelectSender {...props} onClose={close} />);
169
167
  };
170
168
 
package/src/ui/styles.ts CHANGED
@@ -49,7 +49,8 @@ export const ModalContent = styled.div<{ $mobileFullscreen?: boolean }>`
49
49
  @media (max-width: 600px) {
50
50
  max-width: 100%;
51
51
  width: 100%;
52
- max-height: 90%;
52
+ height: auto !important;
53
+ max-height: 95% !important;
53
54
  border-bottom-left-radius: 0;
54
55
  border-bottom-right-radius: 0;
55
56
  border: none;