@hot-labs/kit 1.2.0-alpha.2 → 1.2.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 (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 +4 -1
  47. package/build/exchange.js +24 -30
  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 +150 -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 +22 -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 +6 -0
  180. package/build/ui/uikit/text.js +59 -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 +24 -30
  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 +309 -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 +50 -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 +64 -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
@@ -1,25 +1,38 @@
1
1
  import { useCallback, useEffect, useRef, useState } from "react";
2
- import styled, { keyframes } from "styled-components";
2
+ import styled from "styled-components";
3
3
  import { observer } from "mobx-react-lite";
4
4
  import uuid4 from "uuid4";
5
5
 
6
- import { SwitchIcon } from "../icons/switch";
6
+ import RefreshIcon from "../icons/refresh";
7
7
  import { ArrowRightIcon } from "../icons/arrow-right";
8
8
 
9
+ import { HotConnector } from "../../HotConnector";
10
+ import { BridgeReview } from "../../exchange";
11
+ import { OmniWallet } from "../../OmniWallet";
12
+
9
13
  import { formatter } from "../../core/utils";
10
14
  import { tokens } from "../../core/tokens";
11
15
  import { Recipient } from "../../core/recipient";
12
- import { OmniWallet } from "../../OmniWallet";
13
- import { BridgeReview } from "../../exchange";
14
- import { HotConnector } from "../../HotConnector";
15
- import { WalletType } from "../../core/chains";
16
+ import { chains, WalletType } from "../../core/chains";
16
17
  import { Token } from "../../core/token";
17
18
 
18
19
  import Popup from "../Popup";
19
20
  import { PopupButton } from "../styles";
20
- import { openSelectRecipient, openSelectTokenPopup, openSelectSender } from "../router";
21
+ import DepositQR from "../profile/DepositQR";
22
+ import { openSelectRecipient, openSelectSender, openSelectTokenPopup, openWalletPicker } from "../router";
21
23
  import { TokenIcon } from "./TokenCard";
22
- import DepositQR from "./DepositQR";
24
+
25
+ import { PLarge, PMedium, PSmall, PTiny } from "../uikit/text";
26
+ import { Skeleton } from "../uikit/loader";
27
+ import { ImageView } from "../uikit/image";
28
+ import ExchangeIcon from "../icons/exchange";
29
+ import { ActionButton, Button } from "../uikit/button";
30
+
31
+ const animations = {
32
+ success: "https://hex.exchange/success.json",
33
+ failed: "https://hex.exchange/error.json",
34
+ loading: "https://hex.exchange/loading.json",
35
+ };
23
36
 
24
37
  export interface BridgeProps {
25
38
  hot: HotConnector;
@@ -48,7 +61,7 @@ const FIXED = 6;
48
61
  export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSelectPair }: BridgeProps) => {
49
62
  const [isFiat, setIsFiat] = useState(false);
50
63
  const [type, setType] = useState<"exactIn" | "exactOut">(setup?.type || "exactIn");
51
- const [value, setValue] = useState<string>(setup?.amount?.toString() ?? "");
64
+ const [value, setValue] = useState<string>(setup?.amount?.toFixed(6) ?? "");
52
65
  const [from, setFrom] = useState<Token>(setup?.from || tokens.list.find((t) => t.id === localStorage.getItem("bridge:from")) || tokens.list.find((t) => t.symbol === "NEAR")!);
53
66
  const [to, setTo] = useState<Token>(setup?.to || tokens.list.find((t) => t.id === localStorage.getItem("bridge:to")) || tokens.list.find((t) => t.symbol === "USDT")!);
54
67
 
@@ -56,6 +69,12 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
56
69
  const [isError, setIsError] = useState<string | null>(null);
57
70
  const [isReviewing, setIsReviewing] = useState(false);
58
71
 
72
+ useState(() => {
73
+ fetch(animations.loading);
74
+ fetch(animations.success);
75
+ fetch(animations.failed);
76
+ });
77
+
59
78
  const [processing, setProcessing] = useState<{
60
79
  status: "qr" | "processing" | "success" | "error";
61
80
  resolve?: (value: BridgeReview) => void;
@@ -170,9 +189,16 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
170
189
  log("Signing transaction");
171
190
 
172
191
  const result = await hot.exchange.makeSwap(review, { log });
173
- setProcessing({ status: "success", message: "Transaction signed", review: result });
192
+ let resultReview = result.review;
193
+
194
+ if (result.processing) {
195
+ log("Waiting for transaction to be confirmed");
196
+ resultReview = await result.processing();
197
+ }
198
+
199
+ setProcessing({ status: "success", message: "Transaction signed", review: resultReview });
174
200
  if (setup?.autoClose) onClose();
175
- return result;
201
+ return resultReview;
176
202
  } catch (e) {
177
203
  setProcessing({ status: "error", message: e?.toString?.() ?? "Unknown error", review });
178
204
  throw e;
@@ -220,7 +246,7 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
220
246
  <Popup widget={widget} onClose={onClose} header={<p>{title}</p>} mobileFullscreen={setup?.mobileFullscreen}>
221
247
  <div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
222
248
  {/* @ts-expect-error: dotlottie-wc is not typed */}
223
- <dotlottie-wc key="loading" src="/loading.json" speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
249
+ <dotlottie-wc key="loading" src={animations.loading} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
224
250
  <p style={{ marginTop: -32, fontSize: 16 }}>{processing.message}</p>
225
251
  </div>
226
252
  </Popup>
@@ -232,7 +258,7 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
232
258
  <Popup widget={widget} onClose={onClose} header={<p>{title}</p>} mobileFullscreen={setup?.mobileFullscreen}>
233
259
  <div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
234
260
  {/* @ts-expect-error: dotlottie-wc is not typed */}
235
- <dotlottie-wc key="success" src="/success.json" speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
261
+ <dotlottie-wc key="success" src={animations.success} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
236
262
  <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Exchange successful</p>
237
263
  </div>
238
264
  <PopupButton style={{ marginTop: "auto" }} onClick={() => (cancelReview(), onClose())}>
@@ -247,11 +273,11 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
247
273
  <Popup widget={widget} onClose={onClose} header={<p>{title}</p>} mobileFullscreen={setup?.mobileFullscreen}>
248
274
  <div style={{ width: "100%", height: 400, gap: 8, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
249
275
  {/* @ts-expect-error: dotlottie-wc is not typed */}
250
- <dotlottie-wc key="error" src="/error.json" speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
276
+ <dotlottie-wc key="error" src={animations.failed} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
251
277
  <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Exchange failed</p>
252
278
  <p style={{ fontSize: 14 }}>{processing.message}</p>
253
279
  </div>
254
- <PopupButton onClick={() => (cancelReview(), onClose())}>Continue</PopupButton>
280
+ <ActionButton onClick={() => (cancelReview(), onClose())}>Continue</ActionButton>
255
281
  </Popup>
256
282
  );
257
283
  }
@@ -261,94 +287,125 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
261
287
  if (recipient == null) return <PopupButton disabled>Set recipient</PopupButton>;
262
288
  if (sender !== "qr" && +from.float(hot.balance(sender, from)).toFixed(FIXED) < +amountFrom.toFixed(FIXED)) return <PopupButton disabled>Insufficient balance</PopupButton>;
263
289
  return (
264
- <PopupButton disabled={isReviewing || isError != null} onClick={handleConfirm}>
290
+ <ActionButton style={{ width: "100%", marginTop: 40 }} disabled={isReviewing || isError != null} onClick={handleConfirm}>
265
291
  {isReviewing ? "Quoting..." : isError != null ? isError : "Confirm"}
266
- </PopupButton>
292
+ </ActionButton>
267
293
  );
268
294
  };
269
295
 
270
296
  return (
271
- <Popup widget={widget} onClose={onClose} header={<p>{title}</p>} mobileFullscreen={setup?.mobileFullscreen}>
272
- <div style={{ display: "flex", flexDirection: "column", gap: 32, width: "100%", height: "100%" }}>
273
- <Card>
274
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
297
+ <Popup widget={widget} onClose={onClose} header={<p>{title}</p>} mobileFullscreen={setup?.mobileFullscreen} style={{ background: "#191919" }}>
298
+ <div style={{ display: "flex", flexDirection: "column", gap: 4, width: "100%", height: "100%" }}>
299
+ <Card style={{ borderRadius: "20px 20px 2px 2px" }}>
300
+ <CardHeader>
301
+ <ChainButton onClick={() => openSelectTokenPopup({ hot, onSelect: (token, wallet) => (setFrom(token), setSender(wallet)) })}>
302
+ <PSmall>From</PSmall>
303
+ <ImageView src={chains.get(from.chain)?.logo || ""} alt={from.symbol} size={16} />
304
+ <PSmall>{chains.get(from.chain)?.name}</PSmall>
305
+ <ArrowRightIcon style={{ marginLeft: -8, transform: "rotate(-270deg)" }} color="#ababab" />
306
+ </ChainButton>
307
+
275
308
  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
276
- <p style={{ fontWeight: "bold" }}>{from.chain === -4 ? "Withdraw HEX from:" : "Send from:"}</p>
277
- <BadgeButton onClick={() => openSelectSender({ hot, type: from.type, onSelect: (wallet) => setSender(wallet) })}>
278
- <p>{formatter.truncateAddress(sender === "qr" ? "QR code" : sender?.address ?? "Select sender")}</p>
309
+ <PSmall>Sender:</PSmall>
310
+ <BadgeButton
311
+ onClick={() => {
312
+ if (from.type === WalletType.OMNI) openSelectSender({ hot, type: from.type, onSelect: (sender) => setSender(sender) });
313
+ else openWalletPicker(hot.getWalletConnector(from.type)!, (wallet) => setSender(wallet));
314
+ }}
315
+ >
316
+ <PSmall>{sender == null ? "Select" : sender !== "qr" ? formatter.truncateAddress(sender.address, 8) : "QR"}</PSmall>
279
317
  </BadgeButton>
280
318
  </div>
281
- </div>
282
-
283
- <div style={{ width: "100%", display: "flex", alignItems: "center", gap: 8, justifyContent: "space-between" }}>
284
- <TokenPreview //
285
- token={from}
286
- style={{ pointerEvents: setup?.readonlyFrom ? "none" : "all" }}
287
- onSelect={() => openSelectTokenPopup({ hot, onSelect: (token, wallet) => (setFrom(token), setSender(wallet)) })}
288
- />
289
-
290
- {isReviewing && type === "exactOut" ? (
291
- <SkeletonShine />
292
- ) : (
293
- <input //
294
- name="from"
295
- type="text"
296
- className="input"
297
- autoComplete="off"
298
- autoCapitalize="off"
299
- autoCorrect="off"
300
- readOnly={setup?.readonlyAmount}
301
- value={isFiat ? `$${showAmountFrom}` : showAmountFrom}
302
- onChange={(e) => (setType("exactIn"), setValue(e.target.value))}
303
- placeholder="0"
304
- autoFocus
319
+ </CardHeader>
320
+
321
+ <CardBody>
322
+ <div style={{ width: "100%", display: "flex", alignItems: "center", gap: 8, justifyContent: "space-between" }}>
323
+ <TokenPreview //
324
+ onSelect={() => openSelectTokenPopup({ onSelect: (token, wallet) => (setFrom(token), setSender(wallet)), initialChain: from.chain, hot })}
325
+ style={{ pointerEvents: setup?.readonlyFrom ? "none" : "all" }}
326
+ token={from}
305
327
  />
306
- )}
307
- </div>
308
-
309
- {isFiat && (
310
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
311
- {sender !== "qr" && (
312
- <AvailableBalance>
313
- <p>Balance: ${from.readable(availableBalance, from.usd)}</p>
314
- <RefreshButton onClick={() => sender && hot.fetchToken(from, sender)} />
315
- </AvailableBalance>
316
- )}
317
328
 
318
- {sender === "qr" && <div />}
329
+ {isReviewing && type === "exactOut" ? (
330
+ <Skeleton />
331
+ ) : (
332
+ <input //
333
+ name="from"
334
+ type="text"
335
+ className="input"
336
+ autoComplete="off"
337
+ autoCapitalize="off"
338
+ autoCorrect="off"
339
+ readOnly={setup?.readonlyAmount}
340
+ value={isFiat ? `$${showAmountFrom}` : showAmountFrom}
341
+ onChange={(e) => (setType("exactIn"), setValue(e.target.value))}
342
+ placeholder="0"
343
+ autoFocus
344
+ />
345
+ )}
346
+ </div>
319
347
 
320
- <div style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
321
- {from.usd !== 0 && <p style={{ marginRight: 8 }}>{`${from.readable(amountFrom / from.usd)} ${from.symbol}`}</p>}
322
- {from.usd !== 0 && (
323
- <BadgeButton style={{ border: `1px solid #fff` }} onClick={() => setIsFiat(!isFiat)}>
324
- USD
325
- </BadgeButton>
348
+ {isFiat && (
349
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
350
+ {sender !== "qr" && (
351
+ <AvailableBalance>
352
+ <PSmall>Balance: ${from.readable(availableBalance, from.usd)}</PSmall>
353
+ <Button onClick={() => sender && hot.fetchToken(from, sender)}>
354
+ <RefreshIcon color="#fff" />
355
+ </Button>
356
+ </AvailableBalance>
326
357
  )}
327
- {sender !== "qr" && <BadgeButton onClick={handleMax}>MAX</BadgeButton>}
358
+
359
+ {sender === "qr" && <div />}
360
+
361
+ <div style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
362
+ {from.usd !== 0 && <PSmall style={{ marginRight: 8 }}>{`${from.readable(amountFrom / from.usd)} ${from.symbol}`}</PSmall>}
363
+
364
+ {from.usd !== 0 && (
365
+ <BadgeButton style={{ border: `1px solid #fff` }} onClick={() => setIsFiat(!isFiat)}>
366
+ <PTiny>USD</PTiny>
367
+ </BadgeButton>
368
+ )}
369
+
370
+ {sender !== "qr" && (
371
+ <BadgeButton onClick={handleMax}>
372
+ <PTiny>MAX</PTiny>
373
+ </BadgeButton>
374
+ )}
375
+ </div>
328
376
  </div>
329
- </div>
330
- )}
331
-
332
- {!isFiat && (
333
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
334
- {sender !== "qr" && (
335
- <AvailableBalance>
336
- <p>Balance: {`${from.readable(availableBalance)} ${from.symbol}`}</p>
337
- <RefreshButton onClick={() => sender && hot.fetchToken(from, sender)} />
338
- </AvailableBalance>
339
- )}
340
- {sender === "qr" && <div />}
341
- <div style={{ display: "flex", alignItems: "center", gap: 4 }}>
342
- {from.usd !== 0 && <p style={{ marginRight: 8 }}>${from.readable(amountFrom, from.usd)}</p>}
343
- {from.usd !== 0 && <BadgeButton onClick={() => setIsFiat(!isFiat)}>USD</BadgeButton>}
344
- {sender !== "qr" && <BadgeButton onClick={handleMax}>MAX</BadgeButton>}
377
+ )}
378
+
379
+ {!isFiat && (
380
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
381
+ {sender !== "qr" && (
382
+ <AvailableBalance>
383
+ <PSmall>Balance: {`${from.readable(availableBalance)} ${from.symbol}`}</PSmall>
384
+ <Button style={{ marginTop: 2 }} onClick={() => sender && hot.fetchToken(from, sender)}>
385
+ <RefreshIcon color="#fff" />
386
+ </Button>
387
+ </AvailableBalance>
388
+ )}
389
+ {sender === "qr" && <div />}
390
+ <div style={{ display: "flex", alignItems: "center", gap: 4 }}>
391
+ {from.usd !== 0 && <PSmall style={{ marginRight: 8 }}>${from.readable(amountFrom, from.usd)}</PSmall>}
392
+ {from.usd !== 0 && (
393
+ <BadgeButton onClick={() => setIsFiat(!isFiat)}>
394
+ <PTiny>USD</PTiny>
395
+ </BadgeButton>
396
+ )}
397
+ {sender !== "qr" && (
398
+ <BadgeButton onClick={handleMax}>
399
+ <PTiny>MAX</PTiny>
400
+ </BadgeButton>
401
+ )}
402
+ </div>
345
403
  </div>
346
- </div>
347
- )}
404
+ )}
405
+ </CardBody>
348
406
  </Card>
349
407
 
350
- <div style={{ position: "relative" }}>
351
- <div style={{ width: "100%", height: 1, backgroundColor: "rgba(255, 255, 255, 0.07)" }} />
408
+ <div style={{ position: "relative", height: 1, width: "100%" }}>
352
409
  <SwitchButton
353
410
  onClick={() => {
354
411
  setFrom(to);
@@ -359,57 +416,72 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
359
416
  setValue("");
360
417
  }}
361
418
  >
362
- <SwitchIcon />
419
+ <ExchangeIcon color="#fff" width={22} height={22} style={{ flexShrink: 0, transform: "rotate(270deg)" }} />
363
420
  </SwitchButton>
364
421
  </div>
365
422
 
366
- <Card>
367
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
423
+ <Card style={{ borderRadius: "2px 2px 20px 20px" }}>
424
+ <CardHeader>
425
+ <ChainButton onClick={() => openSelectTokenPopup({ hot, onSelect: (token, wallet) => (setTo(token), setRecipient(wallet)) })}>
426
+ <PSmall>To</PSmall>
427
+ <ImageView src={chains.get(to.chain)?.logo || ""} alt={to.symbol} size={16} />
428
+ <PSmall>{chains.get(to.chain)?.name}</PSmall>
429
+ <ArrowRightIcon style={{ marginLeft: -8, transform: "rotate(-270deg)" }} color="#ababab" />
430
+ </ChainButton>
431
+
368
432
  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
369
- <p style={{ fontWeight: "bold" }}>{to.chain !== -4 ? "To:" : "Deposit HEX to:"}</p>
370
- <BadgeButton onClick={() => openSelectRecipient({ hot, recipient, type: to.type, onSelect: (recipient) => setRecipient(recipient) })}>
371
- <p>{formatter.truncateAddress(recipient?.address ?? "Connect wallet")}</p>
433
+ <PSmall>Recipient:</PSmall>
434
+ <BadgeButton
435
+ onClick={() => {
436
+ if (to.type === WalletType.OMNI) openSelectRecipient({ hot, type: to.type, onSelect: (recipient) => setRecipient(recipient) });
437
+ else openWalletPicker(hot.getWalletConnector(to.type)!, (wallet) => setRecipient(Recipient.fromWallet(wallet)));
438
+ }}
439
+ >
440
+ <PSmall>{recipient == null ? "Select" : formatter.truncateAddress(recipient.address, 8)}</PSmall>
372
441
  </BadgeButton>
373
442
  </div>
374
- </div>
375
-
376
- <div style={{ width: "100%", display: "flex", alignItems: "center", gap: 8, justifyContent: "space-between" }}>
377
- <TokenPreview //
378
- token={to}
379
- style={{ pointerEvents: setup?.readonlyTo ? "none" : "all" }}
380
- onSelect={() =>
381
- openSelectTokenPopup({
382
- hot,
383
- onSelect: (token, wallet) => {
384
- setRecipient(wallet ? Recipient.fromWallet(wallet) : undefined);
385
- setTo(token);
386
- },
387
- })
388
- }
389
- />
390
-
391
- {isReviewing && type === "exactIn" ? (
392
- <SkeletonShine />
393
- ) : (
394
- <input //
395
- name="to"
396
- type="text"
397
- className="input"
398
- autoComplete="off"
399
- autoCapitalize="off"
400
- autoCorrect="off"
401
- readOnly={setup?.readonlyAmount}
402
- value={isFiat ? `$${+(+showAmountTo * to.usd).toFixed(FIXED)}` : showAmountTo}
403
- onChange={(e) => (setType("exactOut"), setValue(e.target.value))}
404
- placeholder="0"
443
+ </CardHeader>
444
+
445
+ <CardBody style={{ borderRadius: "0 0 20px 20px" }}>
446
+ <div style={{ width: "100%", display: "flex", alignItems: "center", gap: 8, justifyContent: "space-between" }}>
447
+ <TokenPreview //
448
+ token={to}
449
+ style={{ pointerEvents: setup?.readonlyTo ? "none" : "all" }}
450
+ onSelect={() =>
451
+ openSelectTokenPopup({
452
+ hot,
453
+ initialChain: to.chain,
454
+ onSelect: (token, wallet) => {
455
+ setRecipient(wallet ? Recipient.fromWallet(wallet) : undefined);
456
+ setTo(token);
457
+ },
458
+ })
459
+ }
405
460
  />
406
- )}
407
- </div>
408
461
 
409
- <div style={{ width: "100%", display: "flex", justifyContent: "flex-end", marginTop: -8 }}>
410
- {isFiat && <p>Receive: ${`${to.readable(amountTo ?? 0)} ${to.symbol}`}</p>}
411
- {!isFiat && <p>Receive: ${to.readable(amountTo ?? 0, to.usd)}</p>}
412
- </div>
462
+ {isReviewing && type === "exactIn" ? (
463
+ <Skeleton />
464
+ ) : (
465
+ <input //
466
+ name="to"
467
+ type="text"
468
+ className="input"
469
+ autoComplete="off"
470
+ autoCapitalize="off"
471
+ autoCorrect="off"
472
+ readOnly={setup?.readonlyAmount}
473
+ value={isFiat ? `$${+(+showAmountTo * to.usd).toFixed(FIXED)}` : showAmountTo}
474
+ onChange={(e) => (setType("exactOut"), setValue(e.target.value))}
475
+ placeholder="0"
476
+ />
477
+ )}
478
+ </div>
479
+
480
+ <div style={{ width: "100%", display: "flex", justifyContent: "flex-end", marginTop: -4 }}>
481
+ {isFiat && <PSmall>To receive: ${`${to.readable(amountTo ?? 0)} ${to.symbol}`}</PSmall>}
482
+ {!isFiat && <PSmall>To receive: ${to.readable(amountTo ?? 0, to.usd)}</PSmall>}
483
+ </div>
484
+ </CardBody>
413
485
  </Card>
414
486
 
415
487
  <div style={{ marginTop: "auto" }}>{button()}</div>
@@ -421,50 +493,60 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
421
493
  const TokenPreview = ({ style, token, onSelect }: { style?: React.CSSProperties; token: Token; onSelect: (token: Token) => void }) => {
422
494
  return (
423
495
  <SelectTokenButton style={style} onClick={() => onSelect(token)}>
424
- <TokenIcon token={token} />
425
- <p style={{ fontSize: 24, fontWeight: "bold" }}>{token.symbol}</p>
496
+ <TokenIcon withoutChain token={token} size={32} />
497
+ <PLarge>{token.symbol}</PLarge>
426
498
  <ArrowRightIcon style={{ flexShrink: 0, position: "absolute", right: 4 }} />
427
499
  </SelectTokenButton>
428
500
  );
429
501
  };
430
502
 
431
503
  const BadgeButton = styled.button`
432
- font-size: 12px;
433
- font-weight: 500;
434
- color: #fff;
435
- background: #282c30;
504
+ display: flex;
505
+ border-radius: 8px;
506
+ border: 1px solid #323232;
436
507
  padding: 4px 8px;
437
- border-radius: 16px;
508
+ background: transparent;
509
+ transition: 0.2s border-color;
438
510
  cursor: pointer;
439
511
  outline: none;
440
- border: none;
441
- border: 1px solid transparent;
442
- transition: 0.2s border-color;
512
+ gap: 4px;
443
513
 
444
514
  &:hover {
445
515
  border-color: #4e4e4e;
446
516
  }
517
+ `;
447
518
 
448
- * {
449
- font-size: 14px;
450
- font-weight: bold;
519
+ const ChainButton = styled.button`
520
+ display: flex;
521
+ align-items: center;
522
+ padding: 0;
523
+ gap: 8px;
524
+ flex-shrink: 0;
525
+ cursor: pointer;
526
+ outline: none;
527
+ border: none;
528
+ background: transparent;
529
+ transition: 0.2s opacity;
530
+
531
+ &:hover {
532
+ opacity: 0.8;
451
533
  }
452
534
  `;
453
535
 
454
536
  const SelectTokenButton = styled.button`
455
537
  display: flex;
456
538
  align-items: center;
457
- gap: 12px;
539
+ gap: 8px;
458
540
  flex-shrink: 0;
459
541
  cursor: pointer;
460
542
  outline: none;
461
543
  border: none;
462
544
  position: relative;
463
545
  background: transparent;
464
- border-radius: 32px;
465
- padding: 8px;
466
- padding-right: 32px;
467
- margin: -8px;
546
+ border-radius: 24px;
547
+ padding: 4px;
548
+ padding-right: 28px;
549
+ margin: -4px;
468
550
  max-width: 160px;
469
551
  transition: 0.2s background-color;
470
552
 
@@ -482,10 +564,10 @@ const SelectTokenButton = styled.button`
482
564
  const AvailableBalance = styled.div`
483
565
  display: flex;
484
566
  align-items: center;
485
- gap: 4;
486
567
  overflow: hidden;
487
568
  max-width: 200px;
488
569
  white-space: nowrap;
570
+ gap: 4px;
489
571
 
490
572
  p {
491
573
  overflow: hidden;
@@ -495,15 +577,17 @@ const AvailableBalance = styled.div`
495
577
  `;
496
578
 
497
579
  const Card = styled.div`
498
- display: flex;
499
- width: 100%;
500
- flex-direction: column;
501
- gap: 16px;
502
- width: 100%;
503
580
  text-align: left;
504
581
  align-items: flex-start;
505
582
  justify-content: center;
506
- border-radius: 12px;
583
+ flex-direction: column;
584
+
585
+ display: flex;
586
+ width: 100%;
587
+
588
+ border-radius: 20px 20px 2px 2px;
589
+ border: 1px solid #323232;
590
+ background: #1f1f1f;
507
591
 
508
592
  input {
509
593
  outline: none;
@@ -525,77 +609,47 @@ const Card = styled.div`
525
609
  }
526
610
  `;
527
611
 
612
+ const CardHeader = styled.div`
613
+ display: flex;
614
+ align-items: center;
615
+ justify-content: space-between;
616
+ padding: 8px 16px;
617
+ width: 100%;
618
+ gap: 8px;
619
+ `;
620
+
621
+ const CardBody = styled.div`
622
+ padding: 16px;
623
+ width: 100%;
624
+ flex-direction: column;
625
+ align-items: flex-start;
626
+ border-radius: 20px 20px 0 0;
627
+ border-top: 1px solid #323232;
628
+ background: #272727;
629
+ display: flex;
630
+ gap: 8px;
631
+ `;
632
+
528
633
  const SwitchButton = styled.button`
529
634
  position: absolute;
530
635
  left: 50%;
531
636
  top: -18px;
532
637
  transform: translate(-50%, 0);
533
638
  background: #232323;
639
+
534
640
  border-radius: 50%;
535
641
  width: 36px;
536
642
  height: 36px;
643
+
537
644
  display: flex;
538
645
  align-items: center;
539
646
  justify-content: center;
647
+
540
648
  z-index: 2;
541
649
  cursor: pointer;
542
- border: 2px solid #181818;
543
- box-shadow: 0 2px 8px 0 #18181870;
544
650
  outline: none;
545
- border: none;
546
- cursor: pointer;
547
- `;
548
651
 
549
- const shine = keyframes`
550
- 0% {
551
- background-position: -200px 0;
552
- }
553
- 100% {
554
- background-position: calc(200px + 100%) 0;
555
- }
652
+ border-radius: 24px;
653
+ border: 4px solid #191919;
654
+ background: #323232;
556
655
  `;
557
-
558
- const SkeletonShine = styled.div`
559
- display: inline-block;
560
- width: 100px;
561
- height: 40px;
562
- border-radius: 8px;
563
- background: #2e2e2e;
564
- position: relative;
565
- overflow: hidden;
566
-
567
- &:after {
568
- content: "";
569
- display: block;
570
- height: 100%;
571
- width: 100%;
572
- position: absolute;
573
- top: 0;
574
- left: 0;
575
- background: linear-gradient(90deg, rgba(34, 34, 34, 0) 0%, rgba(255, 255, 255, 0.06) 40%, rgba(255, 255, 255, 0.12) 50%, rgba(255, 255, 255, 0.06) 60%, rgba(34, 34, 34, 0) 100%);
576
- background-size: 200px 100%;
577
- animation: ${shine} 1.4s infinite linear;
578
- }
579
- `;
580
-
581
- const RefreshButton = ({ onClick }: { onClick: () => void }) => {
582
- return (
583
- <svg
584
- onClick={onClick}
585
- style={{ width: 18, height: 18, verticalAlign: "middle", marginLeft: 8, cursor: "pointer", opacity: 0.7, transition: "opacity 0.2s" }}
586
- viewBox="0 0 24 24"
587
- fill="none"
588
- stroke="#fff"
589
- strokeWidth="2"
590
- strokeLinecap="round"
591
- strokeLinejoin="round"
592
- onMouseOver={(e) => (e.currentTarget.style.opacity = "1")}
593
- onMouseOut={(e) => (e.currentTarget.style.opacity = "0.7")}
594
- >
595
- <path d="M23 4v6h-6" />
596
- <path d="M1 20v-6h6" />
597
- <path d="M3.51 9a9 9 0 0114.13-3.36L23 10" />
598
- <path d="M20.49 15a9 9 0 01-14.13 3.36L1 14" />
599
- </svg>
600
- );
601
- };