@hot-labs/kit 1.0.33

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 (300) hide show
  1. package/.eslintrc.cjs +11 -0
  2. package/.github/workflows/deploy-example.yml +55 -0
  3. package/.github/workflows/release.yml +74 -0
  4. package/.prettierrc +4 -0
  5. package/.prototools +2 -0
  6. package/.vscode/settings.json +3 -0
  7. package/CHANGELOG.md +1 -0
  8. package/README.md +67 -0
  9. package/build/GoogleConnector.d.ts +20 -0
  10. package/build/GoogleConnector.js +76 -0
  11. package/build/GoogleConnector.js.map +1 -0
  12. package/build/HotConnector.d.ts +91 -0
  13. package/build/HotConnector.js +285 -0
  14. package/build/HotConnector.js.map +1 -0
  15. package/build/OmniConnector.d.ts +95 -0
  16. package/build/OmniConnector.js +123 -0
  17. package/build/OmniConnector.js.map +1 -0
  18. package/build/OmniWallet.d.ts +57 -0
  19. package/build/OmniWallet.js +56 -0
  20. package/build/OmniWallet.js.map +1 -0
  21. package/build/cosmos/connector.d.ts +53 -0
  22. package/build/cosmos/connector.js +207 -0
  23. package/build/cosmos/connector.js.map +1 -0
  24. package/build/cosmos/wallet.d.ts +28 -0
  25. package/build/cosmos/wallet.js +59 -0
  26. package/build/cosmos/wallet.js.map +1 -0
  27. package/build/events.d.ts +42 -0
  28. package/build/events.js +64 -0
  29. package/build/events.js.map +1 -0
  30. package/build/evm/abi.d.ts +17 -0
  31. package/build/evm/abi.js +38 -0
  32. package/build/evm/abi.js.map +1 -0
  33. package/build/evm/connector.d.ts +35 -0
  34. package/build/evm/connector.js +124 -0
  35. package/build/evm/connector.js.map +1 -0
  36. package/build/evm/wallet.d.ts +47 -0
  37. package/build/evm/wallet.js +136 -0
  38. package/build/evm/wallet.js.map +1 -0
  39. package/build/exchange.d.ts +63 -0
  40. package/build/exchange.js +384 -0
  41. package/build/exchange.js.map +1 -0
  42. package/build/hot-wallet/evm.d.ts +1 -0
  43. package/build/hot-wallet/evm.js +33 -0
  44. package/build/hot-wallet/evm.js.map +1 -0
  45. package/build/hot-wallet/hot.d.ts +3 -0
  46. package/build/hot-wallet/hot.js +40 -0
  47. package/build/hot-wallet/hot.js.map +1 -0
  48. package/build/hot-wallet/index.d.ts +4 -0
  49. package/build/hot-wallet/index.js +5 -0
  50. package/build/hot-wallet/index.js.map +1 -0
  51. package/build/hot-wallet/solana/account.d.ts +11 -0
  52. package/build/hot-wallet/solana/account.js +42 -0
  53. package/build/hot-wallet/solana/account.js.map +1 -0
  54. package/build/hot-wallet/solana/index.d.ts +1 -0
  55. package/build/hot-wallet/solana/index.js +85 -0
  56. package/build/hot-wallet/solana/index.js.map +1 -0
  57. package/build/hot-wallet/solana/register.d.ts +2 -0
  58. package/build/hot-wallet/solana/register.js +41 -0
  59. package/build/hot-wallet/solana/register.js.map +1 -0
  60. package/build/hot-wallet/solana/solana-wallet.d.ts +34 -0
  61. package/build/hot-wallet/solana/solana-wallet.js +223 -0
  62. package/build/hot-wallet/solana/solana-wallet.js.map +1 -0
  63. package/build/hot-wallet/solana/utils.d.ts +32 -0
  64. package/build/hot-wallet/solana/utils.js +36 -0
  65. package/build/hot-wallet/solana/utils.js.map +1 -0
  66. package/build/hot-wallet/stellar.d.ts +38 -0
  67. package/build/hot-wallet/stellar.js +32 -0
  68. package/build/hot-wallet/stellar.js.map +1 -0
  69. package/build/hot-wallet/ton.d.ts +1 -0
  70. package/build/hot-wallet/ton.js +49 -0
  71. package/build/hot-wallet/ton.js.map +1 -0
  72. package/build/hot-wallet/wallet.d.ts +1 -0
  73. package/build/hot-wallet/wallet.js +40 -0
  74. package/build/hot-wallet/wallet.js.map +1 -0
  75. package/build/index.d.ts +24 -0
  76. package/build/index.js +25 -0
  77. package/build/index.js.map +1 -0
  78. package/build/near/connector.d.ts +28 -0
  79. package/build/near/connector.js +56 -0
  80. package/build/near/connector.js.map +1 -0
  81. package/build/near/wallet.d.ts +62 -0
  82. package/build/near/wallet.js +233 -0
  83. package/build/near/wallet.js.map +1 -0
  84. package/build/omni/Intents.d.ts +93 -0
  85. package/build/omni/Intents.js +395 -0
  86. package/build/omni/Intents.js.map +1 -0
  87. package/build/omni/bridge.d.ts +3 -0
  88. package/build/omni/bridge.js +34 -0
  89. package/build/omni/bridge.js.map +1 -0
  90. package/build/omni/config.d.ts +99 -0
  91. package/build/omni/config.js +126 -0
  92. package/build/omni/config.js.map +1 -0
  93. package/build/omni/defaultTokens.d.ts +17 -0
  94. package/build/omni/defaultTokens.js +1079 -0
  95. package/build/omni/defaultTokens.js.map +1 -0
  96. package/build/omni/index.d.ts +8 -0
  97. package/build/omni/index.js +9 -0
  98. package/build/omni/index.js.map +1 -0
  99. package/build/omni/nearRpc.d.ts +24 -0
  100. package/build/omni/nearRpc.js +167 -0
  101. package/build/omni/nearRpc.js.map +1 -0
  102. package/build/omni/recipient.d.ts +10 -0
  103. package/build/omni/recipient.js +40 -0
  104. package/build/omni/recipient.js.map +1 -0
  105. package/build/omni/token.d.ts +36 -0
  106. package/build/omni/token.js +136 -0
  107. package/build/omni/token.js.map +1 -0
  108. package/build/omni/tokens.d.ts +14 -0
  109. package/build/omni/tokens.js +57 -0
  110. package/build/omni/tokens.js.map +1 -0
  111. package/build/omni/types.d.ts +41 -0
  112. package/build/omni/types.js +2 -0
  113. package/build/omni/types.js.map +1 -0
  114. package/build/omni/utils.d.ts +24 -0
  115. package/build/omni/utils.js +150 -0
  116. package/build/omni/utils.js.map +1 -0
  117. package/build/settings.d.ts +5 -0
  118. package/build/settings.js +6 -0
  119. package/build/settings.js.map +1 -0
  120. package/build/solana/connector.d.ts +31 -0
  121. package/build/solana/connector.js +138 -0
  122. package/build/solana/connector.js.map +1 -0
  123. package/build/solana/protocol.d.ts +25 -0
  124. package/build/solana/protocol.js +56 -0
  125. package/build/solana/protocol.js.map +1 -0
  126. package/build/solana/wallet.d.ts +47 -0
  127. package/build/solana/wallet.js +188 -0
  128. package/build/solana/wallet.js.map +1 -0
  129. package/build/solana/wallets.d.ts +102 -0
  130. package/build/solana/wallets.js +150 -0
  131. package/build/solana/wallets.js.map +1 -0
  132. package/build/stellar/connector.d.ts +25 -0
  133. package/build/stellar/connector.js +56 -0
  134. package/build/stellar/connector.js.map +1 -0
  135. package/build/stellar/wallet.d.ts +70 -0
  136. package/build/stellar/wallet.js +225 -0
  137. package/build/stellar/wallet.js.map +1 -0
  138. package/build/storage.d.ts +10 -0
  139. package/build/storage.js +12 -0
  140. package/build/storage.js.map +1 -0
  141. package/build/ton/connector.d.ts +25 -0
  142. package/build/ton/connector.js +119 -0
  143. package/build/ton/connector.js.map +1 -0
  144. package/build/ton/utils.d.ts +45 -0
  145. package/build/ton/utils.js +64 -0
  146. package/build/ton/utils.js.map +1 -0
  147. package/build/ton/wallet.d.ts +70 -0
  148. package/build/ton/wallet.js +154 -0
  149. package/build/ton/wallet.js.map +1 -0
  150. package/build/ui/Popup.d.ts +10 -0
  151. package/build/ui/Popup.js +38 -0
  152. package/build/ui/Popup.js.map +1 -0
  153. package/build/ui/connect/AuthPopup.d.ts +2 -0
  154. package/build/ui/connect/AuthPopup.js +48 -0
  155. package/build/ui/connect/AuthPopup.js.map +1 -0
  156. package/build/ui/connect/ConnectWallet.d.ts +9 -0
  157. package/build/ui/connect/ConnectWallet.js +22 -0
  158. package/build/ui/connect/ConnectWallet.js.map +1 -0
  159. package/build/ui/connect/LogoutPopup.d.ts +10 -0
  160. package/build/ui/connect/LogoutPopup.js +8 -0
  161. package/build/ui/connect/LogoutPopup.js.map +1 -0
  162. package/build/ui/connect/WCPopup.d.ts +13 -0
  163. package/build/ui/connect/WCPopup.js +81 -0
  164. package/build/ui/connect/WCPopup.js.map +1 -0
  165. package/build/ui/connect/WCRequest.d.ts +9 -0
  166. package/build/ui/connect/WCRequest.js +13 -0
  167. package/build/ui/connect/WCRequest.js.map +1 -0
  168. package/build/ui/connect/WalletPicker.d.ts +11 -0
  169. package/build/ui/connect/WalletPicker.js +48 -0
  170. package/build/ui/connect/WalletPicker.js.map +1 -0
  171. package/build/ui/icons/arrow-right.d.ts +1 -0
  172. package/build/ui/icons/arrow-right.js +5 -0
  173. package/build/ui/icons/arrow-right.js.map +1 -0
  174. package/build/ui/icons/exchange.d.ts +6 -0
  175. package/build/ui/icons/exchange.js +6 -0
  176. package/build/ui/icons/exchange.js.map +1 -0
  177. package/build/ui/icons/logout.d.ts +1 -0
  178. package/build/ui/icons/logout.js +3 -0
  179. package/build/ui/icons/logout.js.map +1 -0
  180. package/build/ui/icons/pending.d.ts +1 -0
  181. package/build/ui/icons/pending.js +5 -0
  182. package/build/ui/icons/pending.js.map +1 -0
  183. package/build/ui/icons/qr.d.ts +1 -0
  184. package/build/ui/icons/qr.js +5 -0
  185. package/build/ui/icons/qr.js.map +1 -0
  186. package/build/ui/icons/search.d.ts +1 -0
  187. package/build/ui/icons/search.js +5 -0
  188. package/build/ui/icons/search.js.map +1 -0
  189. package/build/ui/icons/switch.d.ts +1 -0
  190. package/build/ui/icons/switch.js +5 -0
  191. package/build/ui/icons/switch.js.map +1 -0
  192. package/build/ui/icons/wallet.d.ts +1 -0
  193. package/build/ui/icons/wallet.js +5 -0
  194. package/build/ui/icons/wallet.js.map +1 -0
  195. package/build/ui/payment/Bridge.d.ts +27 -0
  196. package/build/ui/payment/Bridge.js +340 -0
  197. package/build/ui/payment/Bridge.js.map +1 -0
  198. package/build/ui/payment/DepositQR.d.ts +9 -0
  199. package/build/ui/payment/DepositQR.js +56 -0
  200. package/build/ui/payment/DepositQR.js.map +1 -0
  201. package/build/ui/payment/Payment.d.ts +16 -0
  202. package/build/ui/payment/Payment.js +50 -0
  203. package/build/ui/payment/Payment.js.map +1 -0
  204. package/build/ui/payment/Profile.d.ts +7 -0
  205. package/build/ui/payment/Profile.js +88 -0
  206. package/build/ui/payment/Profile.js.map +1 -0
  207. package/build/ui/payment/SelectRecipient.d.ts +14 -0
  208. package/build/ui/payment/SelectRecipient.js +68 -0
  209. package/build/ui/payment/SelectRecipient.js.map +1 -0
  210. package/build/ui/payment/SelectSender.d.ts +13 -0
  211. package/build/ui/payment/SelectSender.js +23 -0
  212. package/build/ui/payment/SelectSender.js.map +1 -0
  213. package/build/ui/payment/SelectToken.d.ts +13 -0
  214. package/build/ui/payment/SelectToken.js +92 -0
  215. package/build/ui/payment/SelectToken.js.map +1 -0
  216. package/build/ui/payment/TokenCard.d.ts +23 -0
  217. package/build/ui/payment/TokenCard.js +50 -0
  218. package/build/ui/payment/TokenCard.js.map +1 -0
  219. package/build/ui/router.d.ts +37 -0
  220. package/build/ui/router.js +56 -0
  221. package/build/ui/router.js.map +1 -0
  222. package/build/ui/styles.d.ts +11 -0
  223. package/build/ui/styles.js +273 -0
  224. package/build/ui/styles.js.map +1 -0
  225. package/package.json +60 -0
  226. package/skill.md +989 -0
  227. package/src/GoogleConnector.ts +102 -0
  228. package/src/HotConnector.ts +344 -0
  229. package/src/OmniConnector.ts +161 -0
  230. package/src/OmniWallet.ts +94 -0
  231. package/src/cosmos/connector.ts +242 -0
  232. package/src/cosmos/wallet.ts +77 -0
  233. package/src/events.ts +66 -0
  234. package/src/evm/abi.ts +39 -0
  235. package/src/evm/connector.ts +139 -0
  236. package/src/evm/wallet.ts +156 -0
  237. package/src/exchange.ts +426 -0
  238. package/src/hot-wallet/evm.ts +38 -0
  239. package/src/hot-wallet/hot.ts +39 -0
  240. package/src/hot-wallet/index.ts +4 -0
  241. package/src/hot-wallet/solana/account.ts +52 -0
  242. package/src/hot-wallet/solana/index.ts +98 -0
  243. package/src/hot-wallet/solana/register.ts +48 -0
  244. package/src/hot-wallet/solana/solana-wallet.ts +280 -0
  245. package/src/hot-wallet/solana/utils.ts +56 -0
  246. package/src/hot-wallet/stellar.ts +39 -0
  247. package/src/hot-wallet/ton.ts +56 -0
  248. package/src/hot-wallet/wallet.ts +44 -0
  249. package/src/index.ts +30 -0
  250. package/src/near/connector.ts +71 -0
  251. package/src/near/wallet.ts +255 -0
  252. package/src/omni/Intents.ts +454 -0
  253. package/src/omni/bridge.ts +38 -0
  254. package/src/omni/config.ts +130 -0
  255. package/src/omni/defaultTokens.ts +1078 -0
  256. package/src/omni/index.ts +8 -0
  257. package/src/omni/nearRpc.ts +187 -0
  258. package/src/omni/recipient.ts +41 -0
  259. package/src/omni/token.ts +125 -0
  260. package/src/omni/tokens.ts +68 -0
  261. package/src/omni/types.ts +46 -0
  262. package/src/omni/utils.ts +163 -0
  263. package/src/settings.ts +5 -0
  264. package/src/solana/connector.ts +151 -0
  265. package/src/solana/protocol.ts +66 -0
  266. package/src/solana/wallet.ts +230 -0
  267. package/src/solana/wallets.ts +243 -0
  268. package/src/stellar/connector.ts +69 -0
  269. package/src/stellar/wallet.ts +267 -0
  270. package/src/storage.ts +19 -0
  271. package/src/ton/connector.ts +138 -0
  272. package/src/ton/utils.ts +73 -0
  273. package/src/ton/wallet.ts +178 -0
  274. package/src/ui/Popup.tsx +62 -0
  275. package/src/ui/connect/AuthPopup.tsx +78 -0
  276. package/src/ui/connect/ConnectWallet.tsx +63 -0
  277. package/src/ui/connect/LogoutPopup.tsx +20 -0
  278. package/src/ui/connect/WCPopup.tsx +122 -0
  279. package/src/ui/connect/WCRequest.tsx +28 -0
  280. package/src/ui/connect/WalletPicker.tsx +92 -0
  281. package/src/ui/icons/arrow-right.tsx +8 -0
  282. package/src/ui/icons/exchange.tsx +17 -0
  283. package/src/ui/icons/logout.tsx +18 -0
  284. package/src/ui/icons/pending.tsx +18 -0
  285. package/src/ui/icons/qr.tsx +12 -0
  286. package/src/ui/icons/search.tsx +18 -0
  287. package/src/ui/icons/switch.tsx +10 -0
  288. package/src/ui/icons/wallet.tsx +18 -0
  289. package/src/ui/payment/Bridge.tsx +582 -0
  290. package/src/ui/payment/DepositQR.tsx +88 -0
  291. package/src/ui/payment/Payment.tsx +78 -0
  292. package/src/ui/payment/Profile.tsx +140 -0
  293. package/src/ui/payment/SelectRecipient.tsx +111 -0
  294. package/src/ui/payment/SelectSender.tsx +60 -0
  295. package/src/ui/payment/SelectToken.tsx +134 -0
  296. package/src/ui/payment/TokenCard.tsx +83 -0
  297. package/src/ui/router.tsx +92 -0
  298. package/src/ui/styles.ts +284 -0
  299. package/tsconfig.json +22 -0
  300. package/vite.config.ts +17 -0
@@ -0,0 +1,178 @@
1
+ import { SendTransactionRequest, SignDataPayload, SignDataResponse } from "@tonconnect/ui";
2
+ import { Address, comment, SenderArguments, toNano } from "@ton/core";
3
+ import { JettonVerificationType } from "@ton-api/client";
4
+ import { toUserFriendlyAddress } from "@tonconnect/ui";
5
+ import { base58, base64, hex } from "@scure/base";
6
+
7
+ import { OmniWallet } from "../OmniWallet";
8
+ import { WalletType } from "../omni/config";
9
+ import { OmniConnector } from "../OmniConnector";
10
+ import { ReviewFee } from "../omni/bridge";
11
+ import { Token } from "../omni/token";
12
+
13
+ import { createJettonTransferMsgParams, tonApi } from "./utils";
14
+
15
+ interface ProtocolWallet {
16
+ sendTransaction?: (params: SendTransactionRequest) => Promise<unknown>;
17
+ signData?: (params: SignDataPayload) => Promise<SignDataResponse>;
18
+ account: { address: string; publicKey?: string };
19
+ }
20
+
21
+ class TonWallet extends OmniWallet {
22
+ readonly type = WalletType.TON;
23
+
24
+ constructor(readonly connector: OmniConnector, readonly wallet: ProtocolWallet) {
25
+ super(connector);
26
+ }
27
+
28
+ get address() {
29
+ if (!this.wallet.account) throw new Error("No account found");
30
+ return toUserFriendlyAddress(this.wallet.account.address);
31
+ }
32
+
33
+ get publicKey() {
34
+ if (!this.wallet.account?.publicKey) throw new Error("No public key found");
35
+ return base58.encode(hex.decode(this.wallet.account.publicKey));
36
+ }
37
+
38
+ get omniAddress() {
39
+ if (!this.wallet.account?.publicKey) throw new Error("No public key found");
40
+ return this.wallet.account.publicKey.toLowerCase();
41
+ }
42
+
43
+ async fetchBalances(): Promise<Record<string, bigint>> {
44
+ const native = await this.fetchBalance(1111, "native");
45
+ const { balances } = await tonApi.accounts.getAccountJettonsBalances(Address.parse(this.address), { supported_extensions: ["custom_payload"] });
46
+ const list: Record<string, bigint> = {};
47
+
48
+ balances.map((data) => {
49
+ const jetton = data.jetton.address.toString();
50
+ const isScam = data.walletAddress.isScam || data.jetton.verification === JettonVerificationType.Blacklist;
51
+ if (isScam) return;
52
+ list[jetton] = BigInt(data.balance);
53
+ });
54
+
55
+ return { ...list, native };
56
+ }
57
+
58
+ async fetchBalance(_: number, address: string) {
59
+ const owner = Address.parse(this.address);
60
+
61
+ if (address === "native") {
62
+ const balance = await tonApi.accounts.getAccount(owner);
63
+ return BigInt(balance.balance);
64
+ }
65
+
66
+ const jetton = await tonApi.accounts.getAccountJettonBalance(owner, Address.parse(address), { supported_extensions: ["custom_payload"] });
67
+ return BigInt(jetton.balance);
68
+ }
69
+
70
+ async waitNextSeqno(seqno: number): Promise<number> {
71
+ await new Promise((resolve) => setTimeout(resolve, 3000));
72
+ const nextSeqno = await tonApi.wallet.getAccountSeqno(Address.parse(this.address)).catch(() => ({ seqno: 0 }));
73
+ if (seqno >= nextSeqno.seqno) return await this.waitNextSeqno(seqno);
74
+ return nextSeqno.seqno;
75
+ }
76
+
77
+ async waitTransactionByMessageHash(pending: { prevHash: string; seqno: number; timestamp: number; lt: bigint }, attemps = 0): Promise<string> {
78
+ if (attemps > 3) return "";
79
+
80
+ await new Promise((resolve) => setTimeout(resolve, 5000));
81
+ const res = await tonApi.blockchain.getBlockchainAccountTransactions(Address.parse(this.address), { limit: 1, after_lt: BigInt(pending.lt) });
82
+
83
+ const tx = res.transactions[0];
84
+ if (tx.hash === pending.prevHash) return await this.waitTransactionByMessageHash(pending, attemps + 1);
85
+ if (!tx.success) throw tx.computePhase?.exitCodeDescription || "Transaction failed";
86
+ return tx.hash;
87
+ }
88
+
89
+ async sendTransaction(msgs: SenderArguments[]) {
90
+ if (!this.wallet.sendTransaction) throw "Not impl";
91
+ const response = await tonApi.blockchain.getBlockchainAccountTransactions(Address.parse(this.address), { limit: 1 });
92
+ const { seqno } = await tonApi.wallet.getAccountSeqno(Address.parse(this.address));
93
+ const lastTransaction = response.transactions[0];
94
+
95
+ await this.wallet.sendTransaction({
96
+ validUntil: Date.now() + 200_000,
97
+ messages: msgs.map((tx) => ({
98
+ address: tx.to.toString({ bounceable: tx.bounce ? true : false }),
99
+ payload: tx.body?.toBoc().toString("base64"),
100
+ stateInit: tx.init?.data?.toBoc().toString("base64"),
101
+ amount: String(tx.value),
102
+ })),
103
+ });
104
+
105
+ await this.waitNextSeqno(seqno);
106
+ return await this.waitTransactionByMessageHash({
107
+ timestamp: Date.now(),
108
+ lt: lastTransaction.lt,
109
+ prevHash: lastTransaction.hash,
110
+ seqno,
111
+ });
112
+ }
113
+ async transferFee(): Promise<ReviewFee> {
114
+ return new ReviewFee({ baseFee: toNano(0.005), reserve: toNano(0.05), chain: 1111 });
115
+ }
116
+
117
+ async transfer(args: { token: Token; receiver: string; amount: bigint; comment?: string; gasFee?: ReviewFee }) {
118
+ const memo = args.comment ? comment(args.comment) : null;
119
+
120
+ if (args.token.address === "native") {
121
+ const msg = { to: Address.parse(args.receiver), sendMode: 3, bounce: false, value: args.amount, body: memo };
122
+ const tx = await this.sendTransaction([msg]);
123
+ return tx;
124
+ }
125
+
126
+ // Jetton transfer
127
+ const msg = await createJettonTransferMsgParams({
128
+ recipient: Address.parse(args.receiver),
129
+ jetton: Address.parse(args.token.address),
130
+ address: Address.parse(this.address),
131
+ forwardPayload: memo,
132
+ amount: args.amount,
133
+ });
134
+
135
+ const tx = await this.sendTransaction([msg]);
136
+ return tx;
137
+ }
138
+
139
+ async signIntentsWithAuth(domain: string, intents?: Record<string, unknown>[]) {
140
+ const address = this.wallet.account?.address;
141
+ if (!address) throw new Error("Wallet not connected");
142
+
143
+ const seed = hex.encode(window.crypto.getRandomValues(new Uint8Array(32)));
144
+ const msgBuffer = new TextEncoder().encode(`${domain}_${seed}`);
145
+ const nonce = await window.crypto.subtle.digest("SHA-256", new Uint8Array(msgBuffer));
146
+
147
+ return {
148
+ signed: await this.signIntents(intents || [], { nonce: new Uint8Array(nonce) }),
149
+ publicKey: `ed25519:${this.publicKey}`,
150
+ chainId: WalletType.TON,
151
+ address: address,
152
+ seed,
153
+ };
154
+ }
155
+
156
+ async signIntents(intents: Record<string, unknown>[], options?: { deadline?: number; nonce?: Uint8Array }) {
157
+ if (!this.wallet.signData) throw "Not impl";
158
+ const nonce = new Uint8Array(options?.nonce || window.crypto.getRandomValues(new Uint8Array(32)));
159
+ const message = {
160
+ deadline: new Date(Date.now() + 24 * 3_600_000 * 365).toISOString(),
161
+ signer_id: this.omniAddress,
162
+ verifying_contract: "intents.near",
163
+ nonce: base64.encode(nonce),
164
+ intents,
165
+ };
166
+
167
+ const result = await this.wallet.signData({ text: JSON.stringify(message), type: "text" });
168
+
169
+ return {
170
+ ...result,
171
+ standard: "ton_connect",
172
+ signature: "ed25519:" + base58.encode(base64.decode(result.signature)),
173
+ public_key: `ed25519:${this.publicKey}`,
174
+ };
175
+ }
176
+ }
177
+
178
+ export default TonWallet;
@@ -0,0 +1,62 @@
1
+ import { createRoot } from "react-dom/client";
2
+ import React, { useEffect, useRef } from "react";
3
+ import { PopupRoot, ModalContainer, ModalContent, ModalHeader, ModalBody, Footer, GetWalletLink, ModalOverlay } from "./styles";
4
+
5
+ export const present = (render: (close: () => void) => React.ReactNode) => {
6
+ const div = document.createElement("div");
7
+ div.className = "wibe3-popup";
8
+ document.body.appendChild(div);
9
+ const root = createRoot(div);
10
+
11
+ root.render(
12
+ render(() => {
13
+ root.unmount();
14
+ div.remove();
15
+ })
16
+ );
17
+ };
18
+
19
+ const Popup = ({ widget, children, header, onClose, style }: { widget?: boolean; children: React.ReactNode; header?: React.ReactNode; onClose: () => void; style?: React.CSSProperties }) => {
20
+ const containerRef = useRef<HTMLDivElement>(null);
21
+ const contentRef = useRef<HTMLDivElement>(null);
22
+
23
+ useEffect(() => {
24
+ if (widget) return;
25
+ setTimeout(() => {
26
+ if (containerRef.current) {
27
+ containerRef.current.style.opacity = "1";
28
+ containerRef.current.style.transform = "translateY(0)";
29
+ }
30
+
31
+ if (contentRef.current) {
32
+ contentRef.current.style.opacity = "1";
33
+ contentRef.current.style.transform = "translateY(0)";
34
+ }
35
+ }, 100);
36
+ }, []);
37
+
38
+ if (widget) {
39
+ return <PopupRoot>{children}</PopupRoot>;
40
+ }
41
+
42
+ return (
43
+ <PopupRoot>
44
+ <ModalContainer>
45
+ <ModalOverlay ref={containerRef} onClick={onClose} style={{ opacity: 0, transition: "all 0.2s ease-in-out" }} />
46
+ <ModalContent ref={contentRef} style={{ opacity: 0, transform: "translateY(20px)", transition: "all 0.2s ease-in-out" }}>
47
+ {header && <ModalHeader>{header}</ModalHeader>}
48
+ <ModalBody style={{ overflowX: "hidden", ...style }}>{children}</ModalBody>
49
+ <Footer>
50
+ <img src="https://tgapp.herewallet.app/images/hot/hot-icon.png" alt="HOT Connector" />
51
+ <p>HOT Connector</p>
52
+ <GetWalletLink href="https://download.hot-labs.org/kit" target="_blank">
53
+ Don't have a wallet?
54
+ </GetWalletLink>
55
+ </Footer>
56
+ </ModalContent>
57
+ </ModalContainer>
58
+ </PopupRoot>
59
+ );
60
+ };
61
+
62
+ export default Popup;
@@ -0,0 +1,78 @@
1
+ import React, { useState } from "react";
2
+ import { OmniWallet } from "../../OmniWallet";
3
+ import Popup, { present } from "../Popup";
4
+ import { PopupButton } from "../styles";
5
+
6
+ interface AuthIntentPopupProps {
7
+ wallet: OmniWallet;
8
+ onApprove: () => Promise<void>;
9
+ onReject: () => void;
10
+ }
11
+
12
+ const Loader: React.FC = () => {
13
+ return (
14
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="48" height="48" style={{ shapeRendering: "auto", display: "block", background: "transparent" }}>
15
+ <circle strokeDasharray="75.39822368615503 27.132741228718345" r="16" strokeWidth="4" stroke="#000" fill="none" cy="50" cx="50">
16
+ <animateTransform keyTimes="0;1" values="0 50 50;360 50 50" dur="1.408450704225352s" repeatCount="indefinite" type="rotate" attributeName="transform" />
17
+ </circle>
18
+ </svg>
19
+ );
20
+ };
21
+
22
+ const AuthIntentPopupComponent: React.FC<AuthIntentPopupProps> = ({ wallet, onApprove, onReject }) => {
23
+ const [loading, setLoading] = useState(false);
24
+
25
+ const handleApprove = async () => {
26
+ try {
27
+ setLoading(true);
28
+ await onApprove();
29
+ setLoading(false);
30
+ } catch (e) {
31
+ setLoading(false);
32
+ throw e;
33
+ }
34
+ };
35
+
36
+ return (
37
+ <Popup header={<p>Authorize {wallet.connector?.name}</p>} onClose={onReject}>
38
+ <p style={{ textAlign: "center", color: "#fff" }}>To verify your account, you need to sign a message, this action is safe, the platform does not have access to your assets.</p>
39
+ <PopupButton
40
+ disabled={loading}
41
+ onClick={handleApprove}
42
+ style={{
43
+ marginTop: "16px",
44
+ display: "flex",
45
+ alignItems: "center",
46
+ justifyContent: "center",
47
+ height: "48px",
48
+ opacity: loading ? 0.5 : 1,
49
+ }}
50
+ >
51
+ {loading ? <Loader /> : "Sign message"}
52
+ </PopupButton>
53
+ </Popup>
54
+ );
55
+ };
56
+
57
+ export const openAuthPopup = <T,>(wallet: OmniWallet, then: () => Promise<T>) => {
58
+ return new Promise<T>((resolve, reject) => {
59
+ present((close) => {
60
+ return (
61
+ <AuthIntentPopupComponent
62
+ wallet={wallet}
63
+ onReject={() => (close(), reject())}
64
+ onApprove={async () => {
65
+ try {
66
+ const result = await then();
67
+ resolve(result);
68
+ } catch (e) {
69
+ reject(e);
70
+ } finally {
71
+ close();
72
+ }
73
+ }}
74
+ />
75
+ );
76
+ });
77
+ });
78
+ };
@@ -0,0 +1,63 @@
1
+ import { observer } from "mobx-react-lite";
2
+
3
+ import { HotConnector } from "../../HotConnector";
4
+ import { ConnectorType, OmniConnector } from "../../OmniConnector";
5
+ import { formatter } from "../../omni/utils";
6
+
7
+ import { ImageView } from "../payment/TokenCard";
8
+ import { PopupOption, PopupOptionInfo } from "../styles";
9
+ import { openWalletPicker } from "../router";
10
+ import { LogoutIcon } from "../icons/logout";
11
+ import Popup from "../Popup";
12
+
13
+ interface MultichainPopupProps {
14
+ hot: HotConnector;
15
+ onClose: () => void;
16
+ }
17
+
18
+ export const Connector = observer(({ hot, onClose }: MultichainPopupProps) => {
19
+ const onechain = hot.connectors.filter((t) => t.type === ConnectorType.WALLET);
20
+ const social = hot.connectors.filter((t) => t.type === ConnectorType.SOCIAL);
21
+
22
+ const selectConnector = async (t: OmniConnector) => {
23
+ if (t.wallets[0]) return t.disconnect();
24
+ if (t.options.length > 0) return [openWalletPicker(t), onClose()];
25
+ await t.connect().finally(() => onClose());
26
+ };
27
+
28
+ return (
29
+ <Popup header={<p>Select network</p>} onClose={onClose}>
30
+ {onechain.map((t) => (
31
+ <PopupOption key={t.id} onClick={() => selectConnector(t)}>
32
+ <ImageView src={t.icon} alt={t.name} size={44} />
33
+ <PopupOptionInfo>
34
+ <p>{t.name}</p>
35
+ {t.wallets[0]?.address && <span className="wallet-address">{formatter.truncateAddress(t.wallets[0].address, 24)}</span>}
36
+ </PopupOptionInfo>
37
+ {t.wallets[0]?.address && <LogoutIcon />}
38
+ </PopupOption>
39
+ ))}
40
+
41
+ {social.length > 0 && (
42
+ <>
43
+ <div style={{ margin: "4px 0", display: "flex", width: "100%", alignItems: "center", justifyContent: "center", gap: "8px" }}>
44
+ <div style={{ height: "1px", flex: 1, background: "rgba(255,255,255,0.1)" }}></div>
45
+ <div>or</div>
46
+ <div style={{ height: "1px", flex: 1, background: "rgba(255,255,255,0.1)" }}></div>
47
+ </div>
48
+
49
+ {social.map((t) => (
50
+ <PopupOption key={t.id} onClick={() => selectConnector(t)}>
51
+ <ImageView src={t.icon} alt={t.name} size={44} />
52
+ <PopupOptionInfo>
53
+ <p>{t.name}</p>
54
+ {t.wallets[0]?.address && <span className="wallet-address">Multichain connected</span>}
55
+ </PopupOptionInfo>
56
+ {t.wallets[0]?.address && <LogoutIcon />}
57
+ </PopupOption>
58
+ ))}
59
+ </>
60
+ )}
61
+ </Popup>
62
+ );
63
+ });
@@ -0,0 +1,20 @@
1
+ import { observer } from "mobx-react-lite";
2
+
3
+ import Popup from "../Popup";
4
+ import { OmniConnector } from "../../OmniConnector";
5
+ import { PopupButton } from "../styles";
6
+
7
+ interface LogoutPopupProps {
8
+ connector: OmniConnector;
9
+ onApprove: () => void;
10
+ onReject: () => void;
11
+ }
12
+
13
+ export const LogoutPopup = observer(({ connector, onApprove, onReject }: LogoutPopupProps) => {
14
+ return (
15
+ <Popup header={<p>Disconnect {connector.name}</p>} onClose={onReject}>
16
+ <p style={{ textAlign: "center", color: "#fff" }}>Your local session will be cleared, see you there!</p>
17
+ <PopupButton onClick={onApprove}>Bye-bye</PopupButton>
18
+ </Popup>
19
+ );
20
+ });
@@ -0,0 +1,122 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ import { observer } from "mobx-react-lite";
3
+ import QRCodeStyling from "qr-code-styling";
4
+ import styled from "styled-components";
5
+
6
+ import Popup from "../Popup";
7
+ import { WC_ICON } from "../../OmniConnector";
8
+
9
+ interface WCPopupProps {
10
+ title: string;
11
+ uri: string;
12
+ icon?: string;
13
+ deeplink?: string;
14
+ onClose: () => void;
15
+ }
16
+
17
+ export const WCPopup = observer(({ title, uri, icon, deeplink, onClose }: WCPopupProps) => {
18
+ const [copyText, setCopyText] = useState("Copy Link");
19
+ const [iconUrl, setIconUrl] = useState<string | null>(WC_ICON);
20
+
21
+ const qrCodeRef = useRef<HTMLDivElement>(null);
22
+ const [qrCode] = useState<QRCodeStyling>(
23
+ new QRCodeStyling({
24
+ data: uri,
25
+ dotsOptions: { color: "#eeeeee", type: "dots" },
26
+ backgroundOptions: { color: "transparent" },
27
+ shape: "square",
28
+ width: 340,
29
+ height: 340,
30
+ type: "svg",
31
+ })
32
+ );
33
+
34
+ useEffect(() => {
35
+ qrCode.update({ data: uri });
36
+ qrCode.append(qrCodeRef.current as HTMLElement);
37
+ }, [uri, qrCode]);
38
+
39
+ useEffect(() => {
40
+ if (!iconUrl) return;
41
+ qrCode.update({ image: iconUrl, imageOptions: { margin: 8, imageSize: 0.2 } });
42
+ }, [iconUrl]);
43
+
44
+ useEffect(() => {
45
+ fetch(icon || WC_ICON)
46
+ .then((res) => res.blob())
47
+ .then(() => setIconUrl(icon || WC_ICON));
48
+ }, [icon]);
49
+
50
+ const handleCopy = async () => {
51
+ if (uri && uri !== "LOADING") {
52
+ await navigator.clipboard.writeText(uri);
53
+ setCopyText("Link Copied");
54
+ setTimeout(() => {
55
+ setCopyText("Copy Link");
56
+ }, 2000);
57
+ }
58
+ };
59
+
60
+ return (
61
+ <Popup header={<p>{title}</p>} onClose={onClose}>
62
+ <div style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "center", gap: 16 }}>
63
+ <div ref={qrCodeRef} style={{ width: 340, height: 340 }}></div>
64
+
65
+ <div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 8 }}>
66
+ <CopyButton onClick={handleCopy}>
67
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-copy" viewBox="0 0 16 16">
68
+ <path
69
+ fillRule="evenodd"
70
+ d="M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1z"
71
+ ></path>
72
+ </svg>
73
+ <p>{copyText}</p>
74
+ </CopyButton>
75
+
76
+ {!!deeplink && (
77
+ <CopyButton onClick={() => window.open(deeplink, "_blank")}>
78
+ <p>Open in {title}</p>
79
+ </CopyButton>
80
+ )}
81
+ </div>
82
+ </div>
83
+ </Popup>
84
+ );
85
+ });
86
+
87
+ export const QrCode = styled.div`
88
+ background: url("https://app.hot-labs.org/assets/QR.svg") center center / cover no-repeat;
89
+ position: relative;
90
+ display: flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ margin: 0 auto;
94
+ width: 400px;
95
+ height: 400px;
96
+ flex-shrink: 0;
97
+
98
+ canvas {
99
+ transform: translate(1px, 22px);
100
+ }
101
+ `;
102
+
103
+ export const CopyButton = styled.div`
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ gap: 8px;
108
+ border: 1px solid #505357;
109
+ transition: background 0.2s ease-in-out;
110
+ background: #282c30;
111
+ padding: 8px;
112
+ border-radius: 16px;
113
+ font-size: 14px;
114
+ font-weight: 500;
115
+ cursor: pointer;
116
+ margin: auto;
117
+ flex-shrink: 0;
118
+
119
+ &:hover {
120
+ background: #383c40;
121
+ }
122
+ `;
@@ -0,0 +1,28 @@
1
+ import { observer } from "mobx-react-lite";
2
+ import { useEffect } from "react";
3
+
4
+ import { ImageView } from "../payment/TokenCard";
5
+ import { PopupButton } from "../styles";
6
+ import Popup from "../Popup";
7
+
8
+ export const WCRequest = observer(({ deeplink, name, icon, onClose, task }: { deeplink?: string; name: string; icon: string; onClose: () => void; task: Promise<any> }) => {
9
+ useEffect(() => {
10
+ task.finally(onClose);
11
+ }, [task]);
12
+
13
+ return (
14
+ <Popup onClose={onClose}>
15
+ <div style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "center", gap: 16 }}>
16
+ <ImageView style={{ marginTop: 32 }} src={icon} alt={name} size={100} />
17
+ <p style={{ fontSize: 24, fontWeight: "bold" }}>{name}</p>
18
+ <p style={{ fontSize: 16, color: "rgba(255, 255, 255, 0.7)" }}>
19
+ Application request you
20
+ <br />
21
+ to approve some action in your wallet
22
+ </p>
23
+
24
+ {!!deeplink && <PopupButton onClick={() => window.open(deeplink, "_blank")}>Open wallet</PopupButton>}
25
+ </div>
26
+ </Popup>
27
+ );
28
+ });
@@ -0,0 +1,92 @@
1
+ import { useState } from "react";
2
+ import { observer } from "mobx-react-lite";
3
+
4
+ import { ImageView } from "../payment/TokenCard";
5
+ import { OmniWallet } from "../../OmniWallet";
6
+ import { OmniConnector, OmniConnectorOption } from "../../OmniConnector";
7
+ import { PopupButton, PopupOption, PopupOptionInfo } from "../styles";
8
+ import { WCPopup } from "./WCPopup";
9
+ import Popup from "../Popup";
10
+
11
+ interface WalletPickerProps {
12
+ initialConnector: OmniConnector | null;
13
+ onSelect?: (wallet: OmniWallet) => void;
14
+ onClose: () => void;
15
+ }
16
+
17
+ export const WalletPicker = observer(({ initialConnector, onSelect, onClose }: WalletPickerProps) => {
18
+ const [connector] = useState<OmniConnector | null>(initialConnector ?? null);
19
+ const [qrcode, setQrcode] = useState<{ uri: string; deeplink?: string; icon?: string } | null>(null);
20
+ const [wallet, setWallet] = useState<OmniConnectorOption | null>(null);
21
+ const [error, setError] = useState<string | null>(null);
22
+ const [loading, setLoading] = useState<boolean>(false);
23
+
24
+ if (qrcode) {
25
+ return (
26
+ <WCPopup //
27
+ title={wallet?.name || "WalletConnect"}
28
+ icon={wallet?.icon || qrcode.icon}
29
+ uri={qrcode.uri}
30
+ onClose={onClose}
31
+ deeplink={qrcode.deeplink}
32
+ />
33
+ );
34
+ }
35
+
36
+ if (wallet != null) {
37
+ return (
38
+ <Popup onClose={onClose}>
39
+ <div style={{ width: "100%", height: 300, display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", gap: 0 }}>
40
+ <ImageView style={{ marginTop: "auto" }} src={wallet.icon} alt={wallet.name} size={100} />
41
+
42
+ <h3 style={{ fontSize: 32, margin: "12px 0 0", fontWeight: "bold", textAlign: "center" }}>{wallet.name}</h3>
43
+ <p style={{ textAlign: "center" }}>{error}</p>
44
+ <PopupButton style={{ marginTop: "auto" }} onClick={() => window.open(wallet.download, "_blank")}>
45
+ {loading ? "Connecting..." : "Get wallet"}
46
+ </PopupButton>
47
+ </div>
48
+ </Popup>
49
+ );
50
+ }
51
+
52
+ if (connector != null) {
53
+ return (
54
+ <Popup header={<p>Select wallet</p>} onClose={onClose}>
55
+ {connector.options.map((wallet) => (
56
+ <PopupOption
57
+ key={wallet.id}
58
+ onClick={async () => {
59
+ try {
60
+ setLoading(true);
61
+ setError(null);
62
+ setWallet(wallet);
63
+
64
+ const instance = await connector.connect(wallet.id);
65
+ if (typeof instance === "object" && "qrcode" in instance) {
66
+ setQrcode({ uri: instance.qrcode, deeplink: instance.deeplink, icon: connector.icon });
67
+ const wallet = await instance.task;
68
+ onSelect?.(wallet);
69
+ onClose();
70
+ return;
71
+ }
72
+
73
+ onSelect?.(instance);
74
+ onClose();
75
+ } catch (e) {
76
+ console.error(e);
77
+ setError(e instanceof Error ? e.message : "Unknown error");
78
+ } finally {
79
+ setLoading(false);
80
+ }
81
+ }}
82
+ >
83
+ <ImageView src={wallet.icon} alt={wallet.name} size={44} />
84
+ <PopupOptionInfo className="connect-item-info">
85
+ <p style={{ fontSize: 20, fontWeight: "bold" }}>{wallet.name}</p>
86
+ </PopupOptionInfo>
87
+ </PopupOption>
88
+ ))}
89
+ </Popup>
90
+ );
91
+ }
92
+ });
@@ -0,0 +1,8 @@
1
+ export const ArrowRightIcon = (props: React.SVGProps<SVGSVGElement>) => {
2
+ return (
3
+ <svg xmlns="http://www.w3.org/2000/svg" width={24} height={24} viewBox="0 0 16 16" fill="none" {...props}>
4
+ <path d="M10.6667 8C10.1282 8 6.66669 8.56 6.66669 12.6667" stroke="#eaeaea" stroke-width="1.2" stroke-linecap="round" />
5
+ <path d="M10.6667 8.00001C10.1282 8.00001 6.66669 7.44001 6.66669 3.33334" stroke="#eaeaea" stroke-width="1.2" stroke-linecap="round" />
6
+ </svg>
7
+ );
8
+ };
@@ -0,0 +1,17 @@
1
+ const ExchangeIcon = ({ size, color, strokeColor }: { size?: number; color?: string; strokeColor?: string }) => {
2
+ return (
3
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
4
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M14 3.5H9C5.41015 3.5 2.5 6.41015 2.5 10V14C2.5 17.5899 5.41015 20.5 9 20.5H14C17.5899 20.5 20.5 17.5899 20.5 14V10C20.5 6.41015 17.5899 3.5 14 3.5Z" fill={color} />
5
+ <path d="M9 3.5H14C17.5899 3.5 20.5 6.41015 20.5 10V14C20.5 17.5899 17.5899 20.5 14 20.5H9C5.41015 20.5 2.5 17.5899 2.5 14V10C2.5 6.41015 5.41015 3.5 9 3.5Z" fill={color} />
6
+ <path d="M9 2.75H15C19.0041 2.75 22.25 5.99594 22.25 10V15C22.25 19.0041 19.0041 22.25 15 22.25H9C4.99594 22.25 1.75 19.0041 1.75 15V10C1.75 5.99594 4.99594 2.75 9 2.75Z" stroke={strokeColor} stroke-width="1.5" />
7
+ <path
8
+ fill-rule="evenodd"
9
+ clip-rule="evenodd"
10
+ d="M14 3.5H9C5.41015 3.5 2.5 6.41015 2.5 10V14C2.5 17.5899 5.41015 20.5 9 20.5H14C17.5899 20.5 20.5 17.5899 20.5 14V10C20.5 6.41015 17.5899 3.5 14 3.5ZM9 2C4.58172 2 1 5.58172 1 10V14C1 18.4183 4.58172 22 9 22H14C18.4183 22 22 18.4183 22 14V10C22 5.58172 18.4183 2 14 2H9ZM9.43398 6.25678C9.84444 6.31237 10.1321 6.69018 10.0765 7.10064C9.88688 8.5013 9.31567 9.52614 8.588 10.25H18C18.4142 10.25 18.75 10.5858 18.75 11C18.75 11.4142 18.4142 11.75 18 11.75H5C4.58579 11.75 4.25 11.4142 4.25 11C4.25 10.5858 4.58579 10.25 5 10.25C5.50127 10.25 6.3231 10.0848 7.05272 9.58232C7.75624 9.09779 8.40283 8.28236 8.59012 6.89936C8.6457 6.48889 9.02351 6.2012 9.43398 6.25678ZM12.9235 17.8994C12.8679 18.3098 13.1556 18.6876 13.566 18.7432C13.9765 18.7988 14.3543 18.5111 14.4099 18.1006C14.5972 16.7176 15.2438 15.9022 15.9473 15.4177C16.6769 14.9152 17.4987 14.75 18 14.75C18.4142 14.75 18.75 14.4142 18.75 14C18.75 13.5858 18.4142 13.25 18 13.25H5C4.58579 13.25 4.25 13.5858 4.25 14C4.25 14.4142 4.58579 14.75 5 14.75H14.412C13.6843 15.4739 13.1131 16.4987 12.9235 17.8994Z"
11
+ fill={strokeColor}
12
+ />
13
+ </svg>
14
+ );
15
+ };
16
+
17
+ export default ExchangeIcon;