@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
@@ -0,0 +1,309 @@
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 { serializeError } from "../utils";
22
+ import { ActionButton, Button } from "../uikit/button";
23
+
24
+ interface PaymentProps {
25
+ intents: Intents;
26
+ title?: string;
27
+ allowedTokens?: string[];
28
+ prepaidAmount: bigint;
29
+ payableToken: Token;
30
+ needAmount: bigint;
31
+ connector: HotConnector;
32
+ onReject: (message: string) => void;
33
+ onConfirm: (args: { depositQoute?: BridgeReview; processing?: () => Promise<BridgeReview> }) => Promise<void>;
34
+ close: () => void;
35
+ }
36
+
37
+ const animations = {
38
+ success: "https://hex.exchange/success.json",
39
+ failed: "https://hex.exchange/error.json",
40
+ loading: "https://hex.exchange/loading.json",
41
+ };
42
+
43
+ const PAY_SLIPPAGE = 0.002;
44
+
45
+ export const Payment = observer(({ connector, intents, title = "Payment", allowedTokens, prepaidAmount, payableToken, needAmount, onReject, onConfirm, close }: PaymentProps) => {
46
+ useState(() => {
47
+ fetch(animations.loading);
48
+ fetch(animations.success);
49
+ fetch(animations.failed);
50
+ });
51
+
52
+ useEffect(() => {
53
+ if (connector.wallets.length !== 0) return;
54
+ openConnector(connector);
55
+ }, [connector.wallets.length]);
56
+
57
+ const [flow, setFlow] = useState<{
58
+ token?: Token;
59
+ wallet?: OmniWallet;
60
+ commitment?: Commitment;
61
+ review?: BridgeReview;
62
+ success?: { depositQoute?: BridgeReview; processing?: () => Promise<BridgeReview> };
63
+ step?: "selectToken" | "sign" | "transfer" | "success" | "error" | "loading";
64
+ loading?: boolean;
65
+ error?: any;
66
+ } | null>(needAmount === 0n ? { step: "transfer" } : null);
67
+
68
+ const paymentTitle = title || `Pay ${payableToken.readable(needAmount)} ${payableToken.symbol}`;
69
+
70
+ const selectToken = async (from: Token, wallet?: OmniWallet) => {
71
+ if (!wallet) return;
72
+
73
+ try {
74
+ setFlow({ token: from, wallet, review: undefined, step: "sign" });
75
+ const review = await connector.exchange.reviewSwap({
76
+ recipient: Recipient.fromWallet(intents.signer)!,
77
+ amount: needAmount + (needAmount * BigInt(Math.floor(PAY_SLIPPAGE * 1000))) / BigInt(1000),
78
+ slippage: PAY_SLIPPAGE,
79
+ sender: wallet,
80
+ refund: wallet,
81
+ type: "exactOut",
82
+ to: payableToken,
83
+ from,
84
+ });
85
+
86
+ setFlow({ token: from, wallet, review, step: "sign" });
87
+ } catch {
88
+ setFlow({ token: from, wallet, error: true, step: "sign" });
89
+ }
90
+ };
91
+
92
+ const signStep = async () => {
93
+ try {
94
+ setFlow((t) => (t ? { ...t, step: "sign", loading: true } : null));
95
+ await intents.sign();
96
+ setFlow((t) => (t ? { ...t, step: "transfer", loading: false } : null));
97
+ } catch (error) {
98
+ console.error(error);
99
+ setFlow((t) => (t ? { ...t, step: "error", loading: false, error } : null));
100
+ throw error;
101
+ }
102
+ };
103
+
104
+ const confirmPaymentStep = async () => {
105
+ try {
106
+ setFlow((t) => (t ? { ...t, step: "loading" } : null));
107
+
108
+ if (flow?.review == null) {
109
+ await intents.sign();
110
+ await onConfirm({});
111
+ setFlow({ loading: false, step: "success" });
112
+ setTimeout(() => close(), 2000);
113
+ return;
114
+ }
115
+
116
+ const result = await connector.exchange.makeSwap(flow.review, { log: () => {} });
117
+ await onConfirm({ depositQoute: result.review, processing: result.processing });
118
+ setFlow({ loading: false, step: "success" });
119
+ setTimeout(() => close(), 2000);
120
+ } catch (error) {
121
+ console.error(error);
122
+ setFlow((t) => (t ? { ...t, step: "error", loading: false, error } : null));
123
+ throw error;
124
+ }
125
+ };
126
+
127
+ if (flow?.step === "success") {
128
+ return (
129
+ <Popup header={<p>{paymentTitle}</p>}>
130
+ <div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
131
+ {/* @ts-expect-error: dotlottie-wc is not typed */}
132
+ <dotlottie-wc key="success" src={animations.success} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
133
+ <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Transaction successful</p>
134
+ </div>
135
+
136
+ <ActionButton style={{ marginTop: "auto" }} onClick={() => close()}>
137
+ Continue
138
+ </ActionButton>
139
+ </Popup>
140
+ );
141
+ }
142
+
143
+ if (flow?.step === "loading") {
144
+ return (
145
+ <Popup header={<p>{paymentTitle}</p>}>
146
+ <div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
147
+ {/* @ts-expect-error: dotlottie-wc is not typed */}
148
+ <dotlottie-wc key="loading" src={animations.loading} speed="1" style={{ marginTop: -64, width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
149
+ <p style={{ fontSize: 24, marginTop: -16, fontWeight: "bold" }}>Transaction processing</p>
150
+ </div>
151
+ </Popup>
152
+ );
153
+ }
154
+
155
+ if (flow?.step === "error") {
156
+ return (
157
+ <Popup header={<p>{paymentTitle}</p>}>
158
+ <div style={{ width: "100%", height: 400, gap: 8, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
159
+ {/* @ts-expect-error: dotlottie-wc is not typed */}
160
+ <dotlottie-wc key="error" src={animations.failed} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
161
+ <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Transaction failed</p>
162
+ <p style={{ fontSize: 14, width: "80%", textAlign: "center", overflowY: "auto", lineBreak: "anywhere" }}>{serializeError(flow.error)}</p>
163
+ </div>
164
+ <ActionButton onClick={() => onReject(serializeError(flow.error))}>Close</ActionButton>
165
+ </Popup>
166
+ );
167
+ }
168
+
169
+ if (flow?.step === "transfer") {
170
+ return (
171
+ <Popup onClose={() => onReject("closed")} header={<p>{paymentTitle}</p>}>
172
+ <HorizontalStepper style={{ marginBottom: 24 }} steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={2} />
173
+
174
+ {prepaidAmount > 0n && <TokenCard token={payableToken} hot={connector} wallet={intents.signer} amount={prepaidAmount} />}
175
+ {prepaidAmount > 0n && flow.token != null && (
176
+ <PlusButton>
177
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
178
+ <rect x="11" y="4" width="2" height="16" rx="1" fill="var(--icon-primary)" />
179
+ <rect x="4" y="11" width="16" height="2" rx="1" fill="var(--icon-primary)" />
180
+ </svg>
181
+ </PlusButton>
182
+ )}
183
+
184
+ {flow.token != null && (
185
+ <TokenCard //
186
+ hot={connector}
187
+ token={flow.token}
188
+ wallet={flow.wallet}
189
+ amount={flow.review == null ? needAmount : flow.review?.amountIn ?? 0n}
190
+ />
191
+ )}
192
+
193
+ <ActionButton style={{ marginTop: 24 }} onClick={confirmPaymentStep}>
194
+ {flow?.loading ? "Confirming..." : "Confirm transaction"}
195
+ </ActionButton>
196
+ </Popup>
197
+ );
198
+ }
199
+
200
+ if (flow?.step === "sign") {
201
+ const rightControl = <div style={{ paddingRight: 4, marginLeft: "auto", alignItems: "flex-end" }}>{flow.error ? <ErrorIcon /> : <Loader />}</div>;
202
+
203
+ return (
204
+ <Popup onClose={() => onReject("closed")} header={<p>{title}</p>}>
205
+ <HorizontalStepper style={{ marginBottom: 12 }} steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={1} />
206
+
207
+ {prepaidAmount > 0n && <TokenCard token={payableToken} hot={connector} wallet={intents.signer} amount={prepaidAmount} />}
208
+ {prepaidAmount > 0n && flow.token != null && (
209
+ <PlusButton>
210
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
211
+ <rect x="11" y="4" width="2" height="16" rx="1" fill="var(--icon-primary)" />
212
+ <rect x="4" y="11" width="16" height="2" rx="1" fill="var(--icon-primary)" />
213
+ </svg>
214
+ </PlusButton>
215
+ )}
216
+
217
+ {flow.token != null && (
218
+ <TokenCard //
219
+ hot={connector}
220
+ token={flow.token}
221
+ wallet={flow.wallet}
222
+ rightControl={flow.review ? undefined : rightControl}
223
+ amount={flow.review == null ? needAmount : flow.review?.amountIn ?? 0n}
224
+ />
225
+ )}
226
+
227
+ {flow.error ? (
228
+ <ActionButton style={{ marginTop: 24 }} onClick={() => setFlow(null)}>
229
+ Select another token
230
+ </ActionButton>
231
+ ) : (
232
+ <ActionButton style={{ marginTop: 24 }} disabled={!flow?.review} onClick={signStep}>
233
+ {flow?.loading ? "Signing..." : flow?.review ? "Sign review" : "Quoting..."}
234
+ </ActionButton>
235
+ )}
236
+ </Popup>
237
+ );
238
+ }
239
+
240
+ const recommendedTokens = connector.walletsTokens.filter((t) => t.token.symbol === "USDT" || t.token.symbol === "USDC");
241
+ const otherTokens = connector.walletsTokens.filter((t) => t.token.symbol !== "USDT" && t.token.symbol !== "USDC");
242
+
243
+ const renderToken = (token: Token, wallet: OmniWallet, balance: bigint) => {
244
+ if (token.id === payableToken.id && connector.priorityWallet?.type === wallet.type) return null;
245
+ const availableBalance = token.float(balance) - token.reserve;
246
+
247
+ // Allow only tokens in the allowedTokens list
248
+ if (allowedTokens != null && !allowedTokens?.includes(token.omniAddress)) return null;
249
+
250
+ // same token as need and enough balance is direct deposit
251
+ if (token.originalChain === payableToken.originalChain && token.originalAddress === payableToken.originalAddress && availableBalance >= payableToken.float(needAmount)) {
252
+ return <TokenCard key={token.id} token={token} onSelect={selectToken} hot={connector} wallet={wallet} />;
253
+ }
254
+
255
+ if (availableBalance * token.usd <= payableToken.usd * payableToken.float(needAmount) * (1 + PAY_SLIPPAGE)) return null;
256
+ return <TokenCard key={token.id} token={token} onSelect={selectToken} hot={connector} wallet={wallet} />;
257
+ };
258
+
259
+ return (
260
+ <Popup onClose={() => onReject("closed")} header={<p>{title}</p>}>
261
+ <HorizontalStepper style={{ marginBottom: 12 }} steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={0} />
262
+
263
+ {recommendedTokens.map(({ token, wallet, balance }) => renderToken(token, wallet, balance))}
264
+ {otherTokens.map(({ token, wallet, balance }) => renderToken(token, wallet, balance))}
265
+
266
+ <PopupOption style={{ marginTop: 8 }} onClick={() => openConnector(connector)}>
267
+ <div style={{ width: 44, height: 44, borderRadius: 16, background: "#000", display: "flex", alignItems: "center", justifyContent: "center" }}>
268
+ <WalletIcon />
269
+ </div>
270
+ <PopupOptionInfo>
271
+ <p>Don't find the right token?</p>
272
+ <span className="wallet-address">Connect another wallet</span>
273
+ </PopupOptionInfo>
274
+ </PopupOption>
275
+ </Popup>
276
+ );
277
+ });
278
+
279
+ const ErrorIcon = () => {
280
+ return (
281
+ <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" }}>
282
+ <circle cx="14" cy="14" r="13" stroke="#E74C3C" strokeWidth="2" />
283
+ <path d="M9 9l10 10M19 9l-10 10" stroke="#E74C3C" strokeWidth="2.5" strokeLinecap="round" />
284
+ </svg>
285
+ );
286
+ };
287
+
288
+ const PlusButton = styled.button`
289
+ position: absolute;
290
+ left: 50%;
291
+ top: 209px;
292
+ transform: translate(-50%, 0);
293
+
294
+ border-radius: 50%;
295
+ width: 36px;
296
+ height: 36px;
297
+
298
+ display: flex;
299
+ align-items: center;
300
+ justify-content: center;
301
+
302
+ z-index: 2;
303
+ cursor: pointer;
304
+ outline: none;
305
+
306
+ border-radius: 24px;
307
+ border: 4px solid #191919;
308
+ background: #292929;
309
+ `;
@@ -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
  `;
package/src/ui/router.tsx CHANGED
@@ -1,34 +1,62 @@
1
1
  import { HotConnector } from "../HotConnector";
2
2
  import { OmniConnector } from "../OmniConnector";
3
- import { BridgeReview } from "../exchange";
4
- import { Token } from "../core/token";
5
3
  import { OmniWallet } from "../OmniWallet";
4
+
5
+ import { BridgeReview } from "../exchange";
6
6
  import { WalletType } from "../core/chains";
7
7
  import { Recipient } from "../core/recipient";
8
+ import { Intents } from "../core/Intents";
9
+ import { Token } from "../core/token";
8
10
 
9
11
  import { present } from "./Popup";
10
- import { Payment } from "./payment/Payment";
12
+ import { SelectTokenPopup } from "./bridge/SelectToken";
13
+ import { SelectRecipient } from "./bridge/SelectRecipient";
14
+ import { SelectSender } from "./bridge/SelectSender";
15
+ import { BridgeProps } from "./bridge/Bridge";
16
+ import { Payment } from "./profile/Payment";
17
+ import { Profile } from "./profile/Profile";
18
+ import { Bridge } from "./bridge/Bridge";
19
+
20
+ import ConnectPrimaryWallet from "./connect/PrimaryWallet";
11
21
  import { LogoutPopup } from "./connect/LogoutPopup";
12
- import { Bridge } from "./payment/Bridge";
13
- import { Profile } from "./payment/Profile";
14
- import { SelectTokenPopup } from "./payment/SelectToken";
15
22
  import { WalletPicker } from "./connect/WalletPicker";
16
- import { BridgeProps } from "./payment/Bridge";
17
23
  import { Connector } from "./connect/ConnectWallet";
18
- import { SelectSender } from "./payment/SelectSender";
19
- import { SelectRecipient } from "./payment/SelectRecipient";
20
24
  import { WCRequest } from "./connect/WCRequest";
25
+ import Toast from "./uikit/Toast";
21
26
 
22
- export const openPayment = (connector: HotConnector, token: Token, amount: bigint, recipient?: Recipient) => {
23
- return new Promise<Promise<BridgeReview>>((resolve, reject) => {
27
+ export const openPayment = (
28
+ connector: HotConnector,
29
+ {
30
+ intents,
31
+ title,
32
+ allowedTokens,
33
+ prepaidAmount,
34
+ payableToken,
35
+ needAmount,
36
+ onConfirm,
37
+ }: {
38
+ intents: Intents;
39
+ title?: string;
40
+ allowedTokens?: string[];
41
+ prepaidAmount: bigint;
42
+ payableToken: Token;
43
+ needAmount: bigint;
44
+ onConfirm: (args: { depositQoute?: BridgeReview; processing?: () => Promise<BridgeReview> }) => Promise<void>;
45
+ }
46
+ ) => {
47
+ return new Promise<void>((resolve, reject) => {
24
48
  present((close) => (
25
49
  <Payment //
26
- onClose={() => (close(), reject(new Error("User rejected")))}
27
- onProcess={(task) => (close(), resolve(task))}
50
+ title={title}
51
+ intents={intents}
28
52
  connector={connector}
29
- token={token}
30
- amount={amount}
31
- recipient={recipient}
53
+ needAmount={needAmount}
54
+ prepaidAmount={prepaidAmount}
55
+ allowedTokens={allowedTokens}
56
+ payableToken={payableToken}
57
+ close={() => (close(), resolve())}
58
+ onReject={() => (close(), reject(new Error("User rejected")))}
59
+ onConfirm={onConfirm}
32
60
  />
33
61
  ));
34
62
  });
@@ -62,7 +90,15 @@ export const openBridge = (hot: HotConnector, setup?: BridgeProps["setup"]) => {
62
90
  };
63
91
 
64
92
  export const openConnector = (hot: HotConnector) => {
65
- present((close) => <Connector hot={hot} onClose={close} />);
93
+ return new Promise<void>((resolve) => {
94
+ present((close) => <Connector hot={hot} onClose={() => (resolve(), close())} />);
95
+ });
96
+ };
97
+
98
+ export const openConnectPrimaryWallet = (hot: HotConnector) => {
99
+ return new Promise<void>((resolve) => {
100
+ present((close) => <ConnectPrimaryWallet hot={hot} onClose={() => (close(), resolve())} />);
101
+ });
66
102
  };
67
103
 
68
104
  export const openProfile = (hot: HotConnector) => {
@@ -90,3 +126,7 @@ export const openWCRequest = <T,>(args: { task: () => Promise<T>; deeplink?: str
90
126
  present((close) => <WCRequest deeplink={args.deeplink} name={args.name} icon={args.icon} onClose={close} task={taskPromise} />);
91
127
  return taskPromise;
92
128
  };
129
+
130
+ export const openToast = (message: string) => {
131
+ return present(() => <Toast message={message} />);
132
+ };