@hot-labs/kit 1.2.0-alpha.2 → 1.2.1

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 (280) hide show
  1. package/README.md +2 -9
  2. package/build/HotConnector.d.ts +8 -7
  3. package/build/HotConnector.js +21 -24
  4. package/build/HotConnector.js.map +1 -1
  5. package/build/OmniConnector.d.ts +5 -0
  6. package/build/OmniConnector.js +5 -5
  7. package/build/OmniConnector.js.map +1 -1
  8. package/build/OmniWallet.d.ts +10 -17
  9. package/build/OmniWallet.js +14 -19
  10. package/build/OmniWallet.js.map +1 -1
  11. package/build/core/Intents.d.ts +53 -43
  12. package/build/core/Intents.js +207 -133
  13. package/build/core/Intents.js.map +1 -1
  14. package/build/core/api.d.ts +30 -2
  15. package/build/core/api.js +43 -10
  16. package/build/core/api.js.map +1 -1
  17. package/build/core/bridge.js +1 -1
  18. package/build/core/bridge.js.map +1 -1
  19. package/build/core/index.d.ts +1 -1
  20. package/build/core/index.js +1 -1
  21. package/build/core/index.js.map +1 -1
  22. package/build/core/telemetry.d.ts +13 -0
  23. package/build/core/telemetry.js +27 -0
  24. package/build/core/telemetry.js.map +1 -0
  25. package/build/core/token.d.ts +1 -0
  26. package/build/core/token.js +3 -0
  27. package/build/core/token.js.map +1 -1
  28. package/build/core/tokens.js +0 -8
  29. package/build/core/tokens.js.map +1 -1
  30. package/build/core/types.d.ts +17 -0
  31. package/build/core/utils.d.ts +1 -0
  32. package/build/core/utils.js +21 -1
  33. package/build/core/utils.js.map +1 -1
  34. package/build/cosmos/connector.d.ts +2 -2
  35. package/build/cosmos/connector.js +17 -21
  36. package/build/cosmos/connector.js.map +1 -1
  37. package/build/cosmos/wallet.d.ts +2 -4
  38. package/build/cosmos/wallet.js +3 -8
  39. package/build/cosmos/wallet.js.map +1 -1
  40. package/build/evm/connector.d.ts +1 -0
  41. package/build/evm/connector.js +4 -0
  42. package/build/evm/connector.js.map +1 -1
  43. package/build/evm/wallet.d.ts +2 -1
  44. package/build/evm/wallet.js +7 -5
  45. package/build/evm/wallet.js.map +1 -1
  46. package/build/exchange.d.ts +6 -1
  47. package/build/exchange.js +34 -33
  48. package/build/exchange.js.map +1 -1
  49. package/build/hot-wallet/google.js +10 -5
  50. package/build/hot-wallet/google.js.map +1 -1
  51. package/build/hot-wallet/proxy.js +2 -2
  52. package/build/hot-wallet/proxy.js.map +1 -1
  53. package/build/index.d.ts +2 -1
  54. package/build/index.js +2 -1
  55. package/build/index.js.map +1 -1
  56. package/build/near/connector.js +2 -2
  57. package/build/near/connector.js.map +1 -1
  58. package/build/{core/nearRpc.d.ts → near/rpc.d.ts} +0 -1
  59. package/build/{core/nearRpc.js → near/rpc.js} +8 -22
  60. package/build/near/rpc.js.map +1 -0
  61. package/build/near/wallet.d.ts +4 -4
  62. package/build/near/wallet.js +36 -30
  63. package/build/near/wallet.js.map +1 -1
  64. package/build/solana/{protocol.d.ts → WalletStandard.d.ts} +1 -1
  65. package/build/solana/{protocol.js → WalletStandard.js} +1 -1
  66. package/build/solana/WalletStandard.js.map +1 -0
  67. package/build/solana/connector.d.ts +1 -1
  68. package/build/solana/connector.js +9 -8
  69. package/build/solana/connector.js.map +1 -1
  70. package/build/solana/injected/solana-wallet.js.map +1 -1
  71. package/build/solana/wallet.d.ts +5 -7
  72. package/build/solana/wallet.js +8 -17
  73. package/build/solana/wallet.js.map +1 -1
  74. package/build/solana/{wallets.js → walletStandartList.js} +1 -1
  75. package/build/solana/walletStandartList.js.map +1 -0
  76. package/build/stellar/connector.d.ts +0 -2
  77. package/build/stellar/connector.js +1 -4
  78. package/build/stellar/connector.js.map +1 -1
  79. package/build/stellar/wallet.d.ts +10 -8
  80. package/build/stellar/wallet.js +12 -16
  81. package/build/stellar/wallet.js.map +1 -1
  82. package/build/ton/connector.d.ts +0 -1
  83. package/build/ton/connector.js +1 -4
  84. package/build/ton/connector.js.map +1 -1
  85. package/build/ton/wallet.d.ts +2 -3
  86. package/build/ton/wallet.js +3 -4
  87. package/build/ton/wallet.js.map +1 -1
  88. package/build/tron/connector.d.ts +51 -0
  89. package/build/tron/connector.js +65 -0
  90. package/build/tron/connector.js.map +1 -0
  91. package/build/tron/index.d.ts +6 -0
  92. package/build/tron/index.js +5 -0
  93. package/build/tron/index.js.map +1 -0
  94. package/build/tron/wallet.d.ts +52 -0
  95. package/build/tron/wallet.js +122 -0
  96. package/build/tron/wallet.js.map +1 -0
  97. package/build/ui/Popup.d.ts +2 -2
  98. package/build/ui/Popup.js +5 -1
  99. package/build/ui/Popup.js.map +1 -1
  100. package/build/ui/bridge/Bridge.js +389 -0
  101. package/build/ui/bridge/Bridge.js.map +1 -0
  102. package/build/ui/{payment → bridge}/SelectRecipient.js +3 -3
  103. package/build/ui/bridge/SelectRecipient.js.map +1 -0
  104. package/build/ui/{payment → bridge}/SelectSender.js +2 -2
  105. package/build/ui/bridge/SelectSender.js.map +1 -0
  106. package/build/ui/{payment → bridge}/SelectToken.js +4 -3
  107. package/build/ui/bridge/SelectToken.js.map +1 -0
  108. package/build/ui/{payment → bridge}/TokenCard.d.ts +7 -9
  109. package/build/ui/bridge/TokenCard.js +65 -0
  110. package/build/ui/bridge/TokenCard.js.map +1 -0
  111. package/build/ui/connect/AuthPopup.js +1 -1
  112. package/build/ui/connect/AuthPopup.js.map +1 -1
  113. package/build/ui/connect/ConnectWallet.d.ts +7 -2
  114. package/build/ui/connect/ConnectWallet.js +7 -7
  115. package/build/ui/connect/ConnectWallet.js.map +1 -1
  116. package/build/ui/connect/PrimaryWallet.d.ts +6 -0
  117. package/build/ui/connect/PrimaryWallet.js +18 -0
  118. package/build/ui/connect/PrimaryWallet.js.map +1 -0
  119. package/build/ui/connect/WCRequest.js +1 -1
  120. package/build/ui/connect/WCRequest.js.map +1 -1
  121. package/build/ui/connect/WalletPicker.js +1 -1
  122. package/build/ui/connect/WalletPicker.js.map +1 -1
  123. package/build/ui/icons/arrow-right.d.ts +3 -1
  124. package/build/ui/icons/arrow-right.js +3 -3
  125. package/build/ui/icons/arrow-right.js.map +1 -1
  126. package/build/ui/icons/close.js +1 -1
  127. package/build/ui/icons/close.js.map +1 -1
  128. package/build/ui/icons/exchange.d.ts +3 -4
  129. package/build/ui/icons/exchange.js +2 -2
  130. package/build/ui/icons/exchange.js.map +1 -1
  131. package/build/ui/icons/logout.js +1 -1
  132. package/build/ui/icons/logout.js.map +1 -1
  133. package/build/ui/icons/pending.js +1 -1
  134. package/build/ui/icons/pending.js.map +1 -1
  135. package/build/ui/icons/plus.d.ts +2 -0
  136. package/build/ui/icons/plus.js +6 -0
  137. package/build/ui/icons/plus.js.map +1 -0
  138. package/build/ui/icons/qr.js +1 -1
  139. package/build/ui/icons/qr.js.map +1 -1
  140. package/build/ui/icons/refresh.d.ts +2 -0
  141. package/build/ui/icons/refresh.js +6 -0
  142. package/build/ui/icons/refresh.js.map +1 -0
  143. package/build/ui/icons/search.js +1 -1
  144. package/build/ui/icons/search.js.map +1 -1
  145. package/build/ui/icons/switch.js +1 -1
  146. package/build/ui/icons/switch.js.map +1 -1
  147. package/build/ui/icons/wallet.js +1 -1
  148. package/build/ui/icons/wallet.js.map +1 -1
  149. package/build/ui/{payment → profile}/DepositQR.js.map +1 -1
  150. package/build/ui/profile/Payment.d.ts +23 -0
  151. package/build/ui/profile/Payment.js +154 -0
  152. package/build/ui/profile/Payment.js.map +1 -0
  153. package/build/ui/profile/Profile.d.ts +7 -0
  154. package/build/ui/profile/Profile.js +135 -0
  155. package/build/ui/profile/Profile.js.map +1 -0
  156. package/build/ui/router.d.ts +19 -5
  157. package/build/ui/router.js +21 -9
  158. package/build/ui/router.js.map +1 -1
  159. package/build/ui/styles.js +4 -11
  160. package/build/ui/styles.js.map +1 -1
  161. package/build/ui/uikit/Stepper.d.ts +13 -0
  162. package/build/ui/uikit/Stepper.js +23 -0
  163. package/build/ui/uikit/Stepper.js.map +1 -0
  164. package/build/ui/uikit/Toast.d.ts +4 -0
  165. package/build/ui/uikit/Toast.js +33 -0
  166. package/build/ui/uikit/Toast.js.map +1 -0
  167. package/build/ui/uikit/button.d.ts +2 -0
  168. package/build/ui/uikit/button.js +52 -0
  169. package/build/ui/uikit/button.js.map +1 -0
  170. package/build/ui/uikit/image.d.ts +6 -0
  171. package/build/ui/uikit/image.js +38 -0
  172. package/build/ui/uikit/image.js.map +1 -0
  173. package/build/ui/uikit/loader.d.ts +2 -0
  174. package/build/ui/uikit/loader.js +50 -0
  175. package/build/ui/uikit/loader.js.map +1 -0
  176. package/build/ui/uikit/tabs.d.ts +12 -0
  177. package/build/ui/uikit/tabs.js +35 -0
  178. package/build/ui/uikit/tabs.js.map +1 -0
  179. package/build/ui/uikit/text.d.ts +7 -0
  180. package/build/ui/uikit/text.js +68 -0
  181. package/build/ui/uikit/text.js.map +1 -0
  182. package/build/ui/utils.d.ts +1 -0
  183. package/build/ui/utils.js +20 -0
  184. package/build/ui/utils.js.map +1 -0
  185. package/package.json +8 -4
  186. package/src/HotConnector.ts +24 -31
  187. package/src/OmniConnector.ts +10 -9
  188. package/src/OmniWallet.ts +24 -25
  189. package/src/core/Intents.ts +222 -151
  190. package/src/core/api.ts +56 -10
  191. package/src/core/bridge.ts +3 -2
  192. package/src/core/index.ts +1 -1
  193. package/src/core/telemetry.ts +28 -0
  194. package/src/core/token.ts +4 -0
  195. package/src/core/tokens.ts +0 -9
  196. package/src/core/types.ts +21 -0
  197. package/src/core/utils.ts +17 -1
  198. package/src/cosmos/connector.ts +22 -26
  199. package/src/cosmos/wallet.ts +3 -8
  200. package/src/evm/connector.ts +5 -0
  201. package/src/evm/wallet.ts +9 -6
  202. package/src/exchange.ts +36 -33
  203. package/src/hot-wallet/google.ts +12 -5
  204. package/src/hot-wallet/proxy.ts +2 -2
  205. package/src/index.ts +3 -1
  206. package/src/near/connector.ts +2 -2
  207. package/src/{core/nearRpc.ts → near/rpc.ts} +9 -23
  208. package/src/near/wallet.ts +39 -31
  209. package/src/solana/{protocol.ts → WalletStandard.ts} +2 -4
  210. package/src/solana/connector.ts +9 -8
  211. package/src/solana/injected/solana-wallet.ts +6 -6
  212. package/src/solana/wallet.ts +11 -20
  213. package/src/stellar/connector.ts +1 -6
  214. package/src/stellar/wallet.ts +17 -17
  215. package/src/ton/connector.ts +1 -5
  216. package/src/ton/wallet.ts +3 -3
  217. package/src/tron/connector.ts +89 -0
  218. package/src/tron/index.ts +7 -0
  219. package/src/tron/wallet.ts +146 -0
  220. package/src/ui/Popup.tsx +12 -4
  221. package/src/ui/{payment → bridge}/Bridge.tsx +266 -212
  222. package/src/ui/{payment → bridge}/SelectRecipient.tsx +5 -4
  223. package/src/ui/{payment → bridge}/SelectSender.tsx +5 -5
  224. package/src/ui/{payment → bridge}/SelectToken.tsx +6 -4
  225. package/src/ui/bridge/TokenCard.tsx +99 -0
  226. package/src/ui/connect/AuthPopup.tsx +1 -1
  227. package/src/ui/connect/ConnectWallet.tsx +16 -10
  228. package/src/ui/connect/PrimaryWallet.tsx +65 -0
  229. package/src/ui/connect/WCRequest.tsx +1 -1
  230. package/src/ui/connect/WalletPicker.tsx +1 -1
  231. package/src/ui/icons/arrow-right.tsx +3 -4
  232. package/src/ui/icons/close.tsx +1 -1
  233. package/src/ui/icons/exchange.tsx +4 -11
  234. package/src/ui/icons/logout.tsx +4 -13
  235. package/src/ui/icons/pending.tsx +2 -4
  236. package/src/ui/icons/plus.tsx +12 -0
  237. package/src/ui/icons/qr.tsx +1 -2
  238. package/src/ui/icons/refresh.tsx +20 -0
  239. package/src/ui/icons/search.tsx +4 -4
  240. package/src/ui/icons/switch.tsx +4 -4
  241. package/src/ui/icons/wallet.tsx +2 -4
  242. package/src/ui/profile/Payment.tsx +329 -0
  243. package/src/ui/{payment → profile}/Profile.tsx +110 -70
  244. package/src/ui/router.tsx +57 -17
  245. package/src/ui/styles.ts +4 -11
  246. package/src/ui/uikit/Stepper.tsx +51 -0
  247. package/src/ui/uikit/Toast.tsx +45 -0
  248. package/src/ui/uikit/button.tsx +53 -0
  249. package/src/ui/uikit/image.tsx +45 -0
  250. package/src/ui/uikit/loader.tsx +52 -0
  251. package/src/ui/uikit/tabs.tsx +56 -0
  252. package/src/ui/uikit/text.tsx +74 -0
  253. package/src/ui/utils.ts +14 -0
  254. package/build/core/nearRpc.js.map +0 -1
  255. package/build/solana/protocol.js.map +0 -1
  256. package/build/solana/wallets.js.map +0 -1
  257. package/build/ui/payment/Bridge.js +0 -358
  258. package/build/ui/payment/Bridge.js.map +0 -1
  259. package/build/ui/payment/Payment.d.ts +0 -16
  260. package/build/ui/payment/Payment.js +0 -50
  261. package/build/ui/payment/Payment.js.map +0 -1
  262. package/build/ui/payment/Profile.d.ts +0 -8
  263. package/build/ui/payment/Profile.js +0 -110
  264. package/build/ui/payment/Profile.js.map +0 -1
  265. package/build/ui/payment/SelectRecipient.js.map +0 -1
  266. package/build/ui/payment/SelectSender.js.map +0 -1
  267. package/build/ui/payment/SelectToken.js.map +0 -1
  268. package/build/ui/payment/TokenCard.js +0 -63
  269. package/build/ui/payment/TokenCard.js.map +0 -1
  270. package/src/ui/payment/Payment.tsx +0 -79
  271. package/src/ui/payment/TokenCard.tsx +0 -98
  272. package/build/solana/{wallets.d.ts → walletStandartList.d.ts} +0 -0
  273. package/build/ui/{payment → bridge}/Bridge.d.ts +3 -3
  274. package/build/ui/{payment → bridge}/SelectRecipient.d.ts +0 -0
  275. package/build/ui/{payment → bridge}/SelectSender.d.ts +2 -2
  276. package/build/ui/{payment → bridge}/SelectToken.d.ts +1 -1
  277. /package/build/ui/{payment → profile}/DepositQR.d.ts +0 -0
  278. /package/build/ui/{payment → profile}/DepositQR.js +0 -0
  279. /package/src/solana/{wallets.ts → walletStandartList.ts} +0 -0
  280. /package/src/ui/{payment → profile}/DepositQR.tsx +0 -0
@@ -0,0 +1,329 @@
1
+ import { observer } from "mobx-react-lite";
2
+ import { useEffect, useState } from "react";
3
+ import styled from "styled-components";
4
+
5
+ import { WalletIcon } from "../icons/wallet";
6
+ import { PopupOption, PopupOptionInfo } from "../styles";
7
+ import { Commitment, Intents } from "../../core";
8
+ import { Recipient } from "../../core/recipient";
9
+ import { Token } from "../../core/token";
10
+
11
+ import { TokenCard } from "../bridge/TokenCard";
12
+ import { BridgeReview } from "../../exchange";
13
+ import { openConnector } from "../router";
14
+
15
+ import { OmniWallet } from "../../OmniWallet";
16
+ import { HotConnector } from "../../HotConnector";
17
+ import Popup from "../Popup";
18
+
19
+ import { Loader } from "../uikit/loader";
20
+ import { HorizontalStepper } from "../uikit/Stepper";
21
+ import { ActionButton } from "../uikit/button";
22
+ import { H6, PSmall } from "../uikit/text";
23
+ import { serializeError } from "../utils";
24
+
25
+ interface PaymentProps {
26
+ onReject: (message: string) => void;
27
+ onConfirm: (args: { depositQoute?: BridgeReview; processing?: () => Promise<BridgeReview> }) => Promise<void>;
28
+ close: () => void;
29
+ allowedTokens?: string[];
30
+ prepaidAmount: bigint;
31
+ payableToken: Token;
32
+ needAmount: bigint;
33
+ connector: HotConnector;
34
+ intents: Intents;
35
+ title?: string;
36
+ }
37
+
38
+ const animations = {
39
+ success: "https://hex.exchange/success.json",
40
+ failed: "https://hex.exchange/error.json",
41
+ loading: "https://hex.exchange/loading.json",
42
+ };
43
+
44
+ const PAY_SLIPPAGE = 0.002;
45
+
46
+ export const Payment = observer(({ connector, intents, title = "Payment", allowedTokens, prepaidAmount, payableToken, needAmount, onReject, onConfirm, close }: PaymentProps) => {
47
+ useState(() => {
48
+ fetch(animations.loading);
49
+ fetch(animations.success);
50
+ fetch(animations.failed);
51
+ });
52
+
53
+ useEffect(() => {
54
+ if (connector.wallets.length !== 0) return;
55
+ openConnector(connector);
56
+ }, [connector.wallets.length]);
57
+
58
+ const [flow, setFlow] = useState<{
59
+ token?: Token;
60
+ wallet?: OmniWallet;
61
+ commitment?: Commitment;
62
+ review?: BridgeReview;
63
+ success?: { depositQoute?: BridgeReview; processing?: () => Promise<BridgeReview> };
64
+ step?: "selectToken" | "sign" | "transfer" | "success" | "error" | "loading";
65
+ loading?: boolean;
66
+ error?: any;
67
+ } | null>(needAmount === 0n ? { step: "transfer" } : null);
68
+
69
+ const paymentTitle = title || `Pay ${payableToken.readable(needAmount)} ${payableToken.symbol}`;
70
+ const showPrepaidToken = payableToken.float(prepaidAmount) * payableToken.usd >= 0.01;
71
+
72
+ const selectToken = async (from: Token, wallet?: OmniWallet) => {
73
+ if (!wallet) return;
74
+
75
+ try {
76
+ setFlow({ token: from, wallet, review: undefined, step: "sign" });
77
+ const insurance = (needAmount * BigInt(Math.floor(PAY_SLIPPAGE * 1000))) / BigInt(1000);
78
+ const extra = connector.exchange.isDirectDeposit(from, payableToken) ? insurance : 0n;
79
+ const review = await connector.exchange.reviewSwap({
80
+ recipient: Recipient.fromWallet(intents.signer)!,
81
+ amount: needAmount + extra,
82
+ slippage: PAY_SLIPPAGE,
83
+ sender: wallet,
84
+ refund: wallet,
85
+ type: "exactOut",
86
+ to: payableToken,
87
+ from,
88
+ });
89
+
90
+ setFlow({ token: from, wallet, review, step: "sign" });
91
+ } catch {
92
+ setFlow({ token: from, wallet, error: true, step: "sign" });
93
+ }
94
+ };
95
+
96
+ const signStep = async () => {
97
+ try {
98
+ setFlow((t) => (t ? { ...t, step: "sign", loading: true } : null));
99
+ await intents.sign();
100
+ setFlow((t) => (t ? { ...t, step: "transfer", loading: false } : null));
101
+ } catch (error) {
102
+ console.error(error);
103
+ setFlow((t) => (t ? { ...t, step: "error", loading: false, error } : null));
104
+ throw error;
105
+ }
106
+ };
107
+
108
+ const confirmPaymentStep = async () => {
109
+ try {
110
+ setFlow((t) => (t ? { ...t, step: "loading" } : null));
111
+
112
+ if (flow?.review == null) {
113
+ await intents.sign();
114
+ await onConfirm({});
115
+ setFlow({ loading: false, step: "success" });
116
+ setTimeout(() => close(), 2000);
117
+ return;
118
+ }
119
+
120
+ const result = await connector.exchange.makeSwap(flow.review, { log: () => {} });
121
+ await onConfirm({ depositQoute: result.review, processing: result.processing });
122
+ setFlow({ loading: false, step: "success" });
123
+ setTimeout(() => close(), 2000);
124
+ } catch (error) {
125
+ console.error(error);
126
+ setFlow((t) => (t ? { ...t, step: "error", loading: false, error } : null));
127
+ throw error;
128
+ }
129
+ };
130
+
131
+ if (flow?.step === "success") {
132
+ return (
133
+ <Popup header={<p>{paymentTitle}</p>}>
134
+ <div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
135
+ {/* @ts-expect-error: dotlottie-wc is not typed */}
136
+ <dotlottie-wc key="success" src={animations.success} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
137
+ <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Transaction successful</p>
138
+ </div>
139
+
140
+ <ActionButton style={{ marginTop: "auto" }} onClick={() => close()}>
141
+ Continue
142
+ </ActionButton>
143
+ </Popup>
144
+ );
145
+ }
146
+
147
+ if (flow?.step === "loading") {
148
+ return (
149
+ <Popup header={<p>{paymentTitle}</p>}>
150
+ <div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
151
+ {/* @ts-expect-error: dotlottie-wc is not typed */}
152
+ <dotlottie-wc key="loading" src={animations.loading} speed="1" style={{ marginTop: -64, width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
153
+ <p style={{ fontSize: 24, marginTop: -16, fontWeight: "bold" }}>Transaction processing</p>
154
+ </div>
155
+ </Popup>
156
+ );
157
+ }
158
+
159
+ if (flow?.step === "error") {
160
+ return (
161
+ <Popup header={<p>{paymentTitle}</p>}>
162
+ <div style={{ width: "100%", height: 400, gap: 8, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
163
+ {/* @ts-expect-error: dotlottie-wc is not typed */}
164
+ <dotlottie-wc key="error" src={animations.failed} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
165
+ <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Transaction failed</p>
166
+ <p style={{ fontSize: 14, width: "80%", textAlign: "center", overflowY: "auto", lineBreak: "anywhere" }}>{serializeError(flow.error)}</p>
167
+ </div>
168
+ <ActionButton onClick={() => onReject(serializeError(flow.error))}>Close</ActionButton>
169
+ </Popup>
170
+ );
171
+ }
172
+
173
+ if (flow?.step === "transfer") {
174
+ return (
175
+ <Popup onClose={() => onReject("closed")} header={<p>{paymentTitle}</p>}>
176
+ <HorizontalStepper style={{ marginBottom: 24 }} steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={2} />
177
+
178
+ <div style={{ textAlign: "left" }}>
179
+ <H6>Confirm transfer</H6>
180
+ <PSmall>Transfer approved. Click confirm to make the payment.</PSmall>
181
+ </div>
182
+
183
+ <div style={{ marginTop: 8, position: "relative", width: "100%" }}>
184
+ {showPrepaidToken && <TokenCard token={payableToken} hot={connector} wallet={intents.signer} amount={prepaidAmount} />}
185
+
186
+ {flow.token != null && (
187
+ <TokenCard //
188
+ hot={connector}
189
+ token={flow.token}
190
+ wallet={flow.wallet}
191
+ amount={flow.review == null ? needAmount : flow.review?.amountIn ?? 0n}
192
+ />
193
+ )}
194
+
195
+ {showPrepaidToken && flow.token != null && (
196
+ <PlusButton>
197
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
198
+ <rect x="11" y="4" width="2" height="16" rx="1" fill="var(--icon-primary)" />
199
+ <rect x="4" y="11" width="16" height="2" rx="1" fill="var(--icon-primary)" />
200
+ </svg>
201
+ </PlusButton>
202
+ )}
203
+ </div>
204
+
205
+ <ActionButton style={{ marginTop: 24 }} onClick={confirmPaymentStep}>
206
+ {flow?.loading ? "Transferring..." : "Confirm transfer"}
207
+ </ActionButton>
208
+ </Popup>
209
+ );
210
+ }
211
+
212
+ if (flow?.step === "sign") {
213
+ const rightControl = <div style={{ paddingRight: 4, marginLeft: "auto", alignItems: "flex-end" }}>{flow.error ? <ErrorIcon /> : <Loader />}</div>;
214
+
215
+ return (
216
+ <Popup onClose={() => onReject("closed")} header={<p>{title}</p>}>
217
+ <HorizontalStepper style={{ marginBottom: 24 }} steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={1} />
218
+
219
+ <div style={{ textAlign: "left" }}>
220
+ <H6>Approve transfer</H6>
221
+ <PSmall>Click the button below to approve the transfer</PSmall>
222
+ </div>
223
+
224
+ <div style={{ marginTop: 8, position: "relative", width: "100%" }}>
225
+ {showPrepaidToken && <TokenCard token={payableToken} hot={connector} wallet={intents.signer} amount={prepaidAmount} />}
226
+
227
+ {flow.token != null && (
228
+ <TokenCard //
229
+ hot={connector}
230
+ token={flow.token}
231
+ wallet={flow.wallet}
232
+ rightControl={flow.review ? undefined : rightControl}
233
+ amount={flow.review == null ? needAmount : flow.review?.amountIn ?? 0n}
234
+ />
235
+ )}
236
+
237
+ {showPrepaidToken && flow.token != null && (
238
+ <PlusButton>
239
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
240
+ <rect x="11" y="4" width="2" height="16" rx="1" fill="var(--icon-primary)" />
241
+ <rect x="4" y="11" width="16" height="2" rx="1" fill="var(--icon-primary)" />
242
+ </svg>
243
+ </PlusButton>
244
+ )}
245
+ </div>
246
+
247
+ {flow.error ? (
248
+ <ActionButton style={{ marginTop: 24 }} onClick={() => setFlow(null)}>
249
+ Select another token
250
+ </ActionButton>
251
+ ) : (
252
+ <ActionButton style={{ marginTop: 24 }} disabled={!flow?.review} onClick={signStep}>
253
+ {flow?.loading ? "Approving..." : flow?.review ? "Approve transfer" : "Quoting..."}
254
+ </ActionButton>
255
+ )}
256
+ </Popup>
257
+ );
258
+ }
259
+
260
+ const recommendedTokens = connector.walletsTokens.filter((t) => t.token.symbol === "USDT" || t.token.symbol === "USDC");
261
+ const otherTokens = connector.walletsTokens.filter((t) => t.token.symbol !== "USDT" && t.token.symbol !== "USDC");
262
+
263
+ const renderToken = (token: Token, wallet: OmniWallet, balance: bigint) => {
264
+ if (token.id === payableToken.id && connector.priorityWallet?.type === wallet.type) return null;
265
+ const availableBalance = token.float(balance) - token.reserve;
266
+
267
+ // Allow only tokens in the allowedTokens list
268
+ if (allowedTokens != null && !allowedTokens?.includes(token.omniAddress)) return null;
269
+
270
+ // same token as need and enough balance is direct deposit
271
+ if (token.originalChain === payableToken.originalChain && token.originalAddress === payableToken.originalAddress && availableBalance >= payableToken.float(needAmount)) {
272
+ return <TokenCard key={token.id} token={token} onSelect={selectToken} hot={connector} wallet={wallet} />;
273
+ }
274
+
275
+ if (availableBalance * token.usd <= payableToken.usd * payableToken.float(needAmount) * (1 + PAY_SLIPPAGE)) return null;
276
+ return <TokenCard key={token.id} token={token} onSelect={selectToken} hot={connector} wallet={wallet} />;
277
+ };
278
+
279
+ return (
280
+ <Popup onClose={() => onReject("closed")} header={<p>{title}</p>}>
281
+ <HorizontalStepper style={{ marginBottom: 24 }} steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={0} />
282
+
283
+ {recommendedTokens.map(({ token, wallet, balance }) => renderToken(token, wallet, balance))}
284
+ {otherTokens.map(({ token, wallet, balance }) => renderToken(token, wallet, balance))}
285
+
286
+ <PopupOption style={{ marginTop: 8 }} onClick={() => openConnector(connector)}>
287
+ <div style={{ width: 44, height: 44, borderRadius: 16, background: "#000", display: "flex", alignItems: "center", justifyContent: "center" }}>
288
+ <WalletIcon />
289
+ </div>
290
+ <PopupOptionInfo>
291
+ <p>Don't find the right token?</p>
292
+ <span className="wallet-address">Connect another wallet</span>
293
+ </PopupOptionInfo>
294
+ </PopupOption>
295
+ </Popup>
296
+ );
297
+ });
298
+
299
+ const ErrorIcon = () => {
300
+ return (
301
+ <svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Failed" style={{ display: "block", margin: "0 auto" }}>
302
+ <circle cx="14" cy="14" r="13" stroke="#E74C3C" strokeWidth="2" />
303
+ <path d="M9 9l10 10M19 9l-10 10" stroke="#E74C3C" strokeWidth="2.5" strokeLinecap="round" />
304
+ </svg>
305
+ );
306
+ };
307
+
308
+ const PlusButton = styled.button`
309
+ position: absolute;
310
+ left: 50%;
311
+ top: 50%;
312
+ transform: translate(-50%, 0);
313
+
314
+ border-radius: 50%;
315
+ width: 30px;
316
+ height: 30px;
317
+
318
+ display: flex;
319
+ align-items: center;
320
+ justify-content: center;
321
+
322
+ z-index: 2;
323
+ cursor: pointer;
324
+ outline: none;
325
+
326
+ border-radius: 24px;
327
+ border: 4px solid #191919;
328
+ background: #292929;
329
+ `;
@@ -1,49 +1,28 @@
1
1
  import { observer } from "mobx-react-lite";
2
2
  import styled from "styled-components";
3
- import { useEffect, useState } from "react";
3
+ import { useEffect } from "react";
4
4
 
5
+ import PlusIcon from "../icons/plus";
5
6
  import { LogoutIcon } from "../icons/logout";
6
- import { openBridge, openConnector } from "../router";
7
- import { HotConnector } from "../../HotConnector";
7
+ import ExchangeIcon from "../icons/exchange";
8
+
8
9
  import { formatter } from "../../core/utils";
9
10
  import { OmniToken } from "../../core/chains";
10
11
  import { tokens } from "../../core/tokens";
11
- import Popup from "../Popup";
12
12
 
13
- import { ImageView, TokenCard, TokenIcon } from "./TokenCard";
14
- import ExchangeIcon from "../icons/exchange";
15
- import { PopupOption } from "../styles";
13
+ import { openBridge, openConnector } from "../router";
14
+ import { HotConnector } from "../../HotConnector";
16
15
 
17
- export const Loader = styled.div`
18
- border: 4px solid #2a2a2a;
19
- border-top: 4px solid #fff;
20
- border-radius: 50%;
21
- width: 24px;
22
- height: 24px;
23
- animation: spin 0.9s linear infinite;
24
- margin: 0 auto;
25
-
26
- @keyframes spin {
27
- 0% {
28
- transform: rotate(0deg);
29
- }
30
- 100% {
31
- transform: rotate(360deg);
32
- }
33
- }
34
- `;
16
+ import { TokenCard, TokenIcon } from "../bridge/TokenCard";
17
+ import { ImageView } from "../uikit/image";
18
+ import { Loader } from "../uikit/loader";
19
+ import { PopupOption } from "../styles";
20
+ import Popup from "../Popup";
35
21
 
36
22
  export const Profile = observer(({ hot, onClose }: { hot: HotConnector; onClose: () => void }) => {
37
23
  let totalBalance = 0;
38
- const tokensList = hot.wallets
39
- .flatMap((wallet) => {
40
- return tokens.list.map((token) => ({ token, wallet, balance: hot.balance(wallet, token) }));
41
- })
42
- .sort((a, b) => {
43
- const balanceA = a.token.float(a.balance) * a.token.usd;
44
- const balanceB = b.token.float(b.balance) * b.token.usd;
45
- return balanceB - balanceA;
46
- })
24
+
25
+ const tokensList = hot.walletsTokens
47
26
  .map(({ token, wallet, balance }) => {
48
27
  if (token.float(balance) < 0.000001) return null;
49
28
  totalBalance += token.float(balance) * token.usd;
@@ -62,7 +41,11 @@ export const Profile = observer(({ hot, onClose }: { hot: HotConnector; onClose:
62
41
  />
63
42
  ),
64
43
  };
65
- });
44
+ })
45
+ .filter((t) => t != null);
46
+
47
+ const omniTokens = tokensList.filter((t) => t.chain === -4);
48
+ const nonOmniTokens = tokensList.filter((t) => t.chain !== -4);
66
49
 
67
50
  useEffect(() => {
68
51
  if (hot.wallets.length > 0) return;
@@ -70,32 +53,43 @@ export const Profile = observer(({ hot, onClose }: { hot: HotConnector; onClose:
70
53
  }, [hot.wallets.length]);
71
54
 
72
55
  return (
73
- <Popup onClose={onClose}>
56
+ <Popup onClose={onClose} style={{ gap: 16 }}>
74
57
  <div style={{ display: "flex", flexWrap: "wrap", width: "100%", gap: 8 }}>
75
- {hot.wallets.map((wallet) => (
76
- <WalletCard onClick={() => wallet.disconnect()}>
77
- <ImageView src={wallet.icon} alt={wallet.connector.name} size={20} />
78
- <div>{formatter.truncateAddress(wallet.address, 8)}</div>
79
- <LogoutIcon width={20} height={20} />
80
- </WalletCard>
81
- ))}
58
+ {hot.connectors.map((connector) =>
59
+ connector.wallets.map((wallet) => (
60
+ <WalletCard onClick={() => connector.disconnect()}>
61
+ <ImageView src={wallet.icon} alt={connector.name} size={20} />
62
+ <div>{formatter.truncateAddress(wallet.address, 8)}</div>
63
+ <LogoutIcon />
64
+ </WalletCard>
65
+ ))
66
+ )}
82
67
 
83
68
  {hot.wallets.length < 6 && (
84
- <WalletCard style={{ paddingLeft: 12, paddingRight: 12 }} onClick={() => openConnector(hot)}>
69
+ <WalletCard style={{ paddingRight: 12 }} onClick={() => openConnector(hot)}>
70
+ <PlusIcon />
85
71
  Add wallet
86
72
  </WalletCard>
87
73
  )}
88
74
  </div>
89
75
 
90
- <div style={{ display: "flex", alignItems: "center", width: "100%", gap: 8, marginTop: 16 }}>
76
+ <Card>
77
+ <PSmall>YOUR BALANCE</PSmall>
91
78
  <BalanceCard>${formatter.amount(totalBalance)}</BalanceCard>
92
- <ExchangeButton onClick={() => (onClose(), openBridge(hot, { title: "Exchange" }))}>
93
- <ExchangeIcon size={32} strokeColor="#d2d2d2" />
94
- </ExchangeButton>
95
- </div>
79
+
80
+ <div style={{ width: "100%", display: "flex", gap: 12, marginTop: 24 }}>
81
+ <ActionButton onClick={() => (onClose(), openBridge(hot, { title: "Exchange" }))}>
82
+ <ExchangeIcon />
83
+ Exchange
84
+ </ActionButton>
85
+ <ActionButton disabled onClick={() => (onClose(), openBridge(hot, { title: "Deposit" }))}>
86
+ Deposit
87
+ </ActionButton>
88
+ </div>
89
+ </Card>
96
90
 
97
91
  {hot.activity.withdrawalsList.length > 0 && (
98
- <TokenCards style={{ marginTop: 16 }}>
92
+ <TokenCards>
99
93
  <p style={{ fontSize: 16, fontWeight: 600, color: "#d2d2d2", textAlign: "left" }}>Pending withdrawals</p>
100
94
  {hot.activity.withdrawalsList.map((withdrawal) => {
101
95
  const token = tokens.get(withdrawal.token as OmniToken, withdrawal.chain);
@@ -119,37 +113,56 @@ export const Profile = observer(({ hot, onClose }: { hot: HotConnector; onClose:
119
113
  </TokenCards>
120
114
  )}
121
115
 
122
- {tokensList.filter((t) => t != null && t.chain === -4).length > 0 && (
123
- <TokenCards style={{ marginTop: 16 }}>
116
+ {omniTokens.length > 0 && (
117
+ <TokenCards>
124
118
  <p style={{ fontSize: 16, fontWeight: 600, color: "#d2d2d2", textAlign: "left" }}>Tokens to withdraw</p>
125
- {tokensList.filter((t) => t != null && t.chain === -4).map((t) => t?.component)}
126
- <div style={{ marginTop: 8, marginBottom: -4, width: "100%", height: 1, background: "#383d42" }}></div>
119
+ {omniTokens.map((t) => t.component)}
127
120
  </TokenCards>
128
121
  )}
129
122
 
130
- {tokensList.filter((t) => t != null && t.chain !== -4).length > 0 && (
131
- <TokenCards style={{ marginTop: 16 }}>
132
- {/* Tokens to exchange */}
133
- {tokensList.filter((t) => t != null && t.chain !== -4).map((t) => t?.component)}
123
+ {nonOmniTokens.length > 0 && (
124
+ <TokenCards>
125
+ <p style={{ fontSize: 16, fontWeight: 600, color: "#d2d2d2", textAlign: "left" }}>Portfolio</p>
126
+ {nonOmniTokens.map((t) => t.component)}
134
127
  </TokenCards>
135
128
  )}
136
129
  </Popup>
137
130
  );
138
131
  });
139
132
 
140
- const ExchangeButton = styled.button`
133
+ const ActionButton = styled.button`
141
134
  display: flex;
142
- align-items: center;
143
- gap: 8px;
144
- cursor: pointer;
145
- outline: none;
135
+ padding: 0 24px;
136
+ border-radius: 12px;
137
+ background: #e7e7e7;
146
138
  border: none;
147
- background: transparent;
148
- padding: 8px;
149
- border-radius: 24px;
139
+ outline: none;
140
+ cursor: pointer;
150
141
  transition: background 0.2s ease-in-out;
142
+ height: 48px;
143
+ display: flex;
144
+ align-items: center;
145
+ justify-content: center;
146
+ gap: 8px;
147
+ flex: 1;
148
+
149
+ color: #121212;
150
+ text-align: center;
151
+ font-family: "Golos Text";
152
+ font-size: 16px;
153
+ font-style: normal;
154
+ font-weight: 500;
155
+ line-height: 22px;
156
+ letter-spacing: -0.16px;
157
+
151
158
  &:hover {
152
- background: rgba(255, 255, 255, 0.1);
159
+ background: #d2d2d2;
160
+ }
161
+
162
+ &:disabled {
163
+ background: #3e3e3e;
164
+ color: #828282;
165
+ cursor: not-allowed;
153
166
  }
154
167
  `;
155
168
 
@@ -168,7 +181,7 @@ const WalletCard = styled.div`
168
181
  border: 1px solid rgba(255, 255, 255, 0.1);
169
182
  padding: 6px;
170
183
  padding-left: 8px;
171
- padding-right: 12px;
184
+ padding-right: 8px;
172
185
  background: #1a1a1a;
173
186
  cursor: pointer;
174
187
  transition: background 0.2s ease-in-out;
@@ -179,7 +192,34 @@ const WalletCard = styled.div`
179
192
  `;
180
193
 
181
194
  const BalanceCard = styled.h2`
182
- font-size: 48px;
183
- font-weight: 600;
184
195
  color: #fff;
196
+ font-family: "Golos Text";
197
+ font-size: 32px;
198
+ font-style: normal;
199
+ font-weight: 600;
200
+ line-height: 44px;
201
+ text-align: left;
202
+ margin: 0;
203
+ `;
204
+
205
+ const PSmall = styled.p`
206
+ color: #bfbfbf;
207
+ font-family: "Golos Text";
208
+ font-size: 14px;
209
+ font-style: normal;
210
+ font-weight: 400;
211
+ line-height: 20px;
212
+ letter-spacing: -0.14px;
213
+ text-align: left;
214
+ margin: 0;
215
+ `;
216
+
217
+ const Card = styled.div`
218
+ display: flex;
219
+ padding: 12px;
220
+ flex-direction: column;
221
+ border-radius: 16px;
222
+ border: 1px solid #323232;
223
+ background: #272727;
224
+ width: 100%;
185
225
  `;