@rabbitio/ui-kit 1.0.0-beta.12 → 1.0.0-beta.121

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 (402) hide show
  1. package/.env.example +1 -0
  2. package/.gitlab-ci.yml +29 -0
  3. package/.husky/commit-msg +19 -0
  4. package/.husky/pre-push +1 -0
  5. package/README.md +14 -4
  6. package/coverage/base.css +224 -0
  7. package/coverage/block-navigation.js +87 -0
  8. package/coverage/clover.xml +19749 -0
  9. package/coverage/coverage-final.json +122 -0
  10. package/coverage/favicon.png +0 -0
  11. package/coverage/index.html +1001 -0
  12. package/coverage/prettify.css +1 -0
  13. package/coverage/prettify.js +2 -0
  14. package/coverage/rabbit-ui-kit/index.html +116 -0
  15. package/coverage/rabbit-ui-kit/index.js.html +88 -0
  16. package/coverage/rabbit-ui-kit/src/common-apis/adapters/analyticsAdapters/googleAnalyticsAdapter.js.html +151 -0
  17. package/coverage/rabbit-ui-kit/src/common-apis/adapters/analyticsAdapters/index.html +146 -0
  18. package/coverage/rabbit-ui-kit/src/common-apis/adapters/analyticsAdapters/metrikaAdapter.js.html +172 -0
  19. package/coverage/rabbit-ui-kit/src/common-apis/adapters/analyticsAdapters/mixpanelAdapter.js.html +199 -0
  20. package/coverage/rabbit-ui-kit/src/common-apis/adapters/axiosAdapter.js.html +190 -0
  21. package/coverage/rabbit-ui-kit/src/common-apis/adapters/index.html +131 -0
  22. package/coverage/rabbit-ui-kit/src/common-apis/adapters/qrUtils.js.html +139 -0
  23. package/coverage/rabbit-ui-kit/src/common-apis/external-apis/apiGroups.js.html +253 -0
  24. package/coverage/rabbit-ui-kit/src/common-apis/external-apis/emailAPI.js.html +133 -0
  25. package/coverage/rabbit-ui-kit/src/common-apis/external-apis/index.html +146 -0
  26. package/coverage/rabbit-ui-kit/src/common-apis/external-apis/ipAddressProviders.js.html +391 -0
  27. package/coverage/rabbit-ui-kit/src/common-apis/globalConstants.jsx.html +94 -0
  28. package/coverage/rabbit-ui-kit/src/common-apis/index.html +116 -0
  29. package/coverage/rabbit-ui-kit/src/common-apis/models/blockchain.js.html +115 -0
  30. package/coverage/rabbit-ui-kit/src/common-apis/models/coin.js.html +829 -0
  31. package/coverage/rabbit-ui-kit/src/common-apis/models/index.html +146 -0
  32. package/coverage/rabbit-ui-kit/src/common-apis/models/protocol.js.html +100 -0
  33. package/coverage/rabbit-ui-kit/src/common-apis/services/fiatCurrenciesService.js.html +544 -0
  34. package/coverage/rabbit-ui-kit/src/common-apis/services/index.html +116 -0
  35. package/coverage/rabbit-ui-kit/src/common-apis/utils/amountUtils.js.html +1234 -0
  36. package/coverage/rabbit-ui-kit/src/common-apis/utils/cache.js.html +811 -0
  37. package/coverage/rabbit-ui-kit/src/common-apis/utils/errorUtils.js.html +211 -0
  38. package/coverage/rabbit-ui-kit/src/common-apis/utils/index.html +191 -0
  39. package/coverage/rabbit-ui-kit/src/common-apis/utils/logging/index.html +131 -0
  40. package/coverage/rabbit-ui-kit/src/common-apis/utils/logging/logger.js.html +211 -0
  41. package/coverage/rabbit-ui-kit/src/common-apis/utils/logging/logsStorage.js.html +268 -0
  42. package/coverage/rabbit-ui-kit/src/common-apis/utils/postponeExecution.js.html +118 -0
  43. package/coverage/rabbit-ui-kit/src/common-apis/utils/rabbitTicker.js.html +157 -0
  44. package/coverage/rabbit-ui-kit/src/common-apis/utils/safeStringify.js.html +235 -0
  45. package/coverage/rabbit-ui-kit/src/index.html +116 -0
  46. package/coverage/rabbit-ui-kit/src/index.js.html +388 -0
  47. package/coverage/rabbit-ui-kit/src/robust-api-caller/cacheAndConcurrentRequestsResolver.js.html +1660 -0
  48. package/coverage/rabbit-ui-kit/src/robust-api-caller/cachedRobustExternalApiCallerService.js.html +526 -0
  49. package/coverage/rabbit-ui-kit/src/robust-api-caller/cancelProcessing.js.html +172 -0
  50. package/coverage/rabbit-ui-kit/src/robust-api-caller/concurrentCalculationsMetadataHolder.js.html +310 -0
  51. package/coverage/rabbit-ui-kit/src/robust-api-caller/externalApiProvider.js.html +553 -0
  52. package/coverage/rabbit-ui-kit/src/robust-api-caller/externalServicesStatsCollector.js.html +319 -0
  53. package/coverage/rabbit-ui-kit/src/robust-api-caller/index.html +206 -0
  54. package/coverage/rabbit-ui-kit/src/robust-api-caller/robustExternalAPICallerService.js.html +997 -0
  55. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/changeHeroSwapProvider.js.html +2800 -0
  56. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/changeNowSwapProvider.js.html +2644 -0
  57. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/exolixSwapProvider.js.html +1942 -0
  58. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/goexmeSwapProvider.js.html +2389 -0
  59. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/index.html +236 -0
  60. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/letsExchangeSwapProvider.js.html +1666 -0
  61. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/retriableErrorsUtils.js.html +274 -0
  62. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapProvider.js.html +1888 -0
  63. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapspaceSwapProvider.js.html +1981 -0
  64. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/utils.js.html +163 -0
  65. package/coverage/rabbit-ui-kit/src/swaps-lib/models/baseSwapCreationInfo.js.html +319 -0
  66. package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwap.js.html +514 -0
  67. package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwapWithFiatData.js.html +529 -0
  68. package/coverage/rabbit-ui-kit/src/swaps-lib/models/index.html +176 -0
  69. package/coverage/rabbit-ui-kit/src/swaps-lib/models/partner.js.html +166 -0
  70. package/coverage/rabbit-ui-kit/src/swaps-lib/models/swapProviderCoinInfo.js.html +337 -0
  71. package/coverage/rabbit-ui-kit/src/swaps-lib/services/index.html +116 -0
  72. package/coverage/rabbit-ui-kit/src/swaps-lib/services/publicSwapService.js.html +1654 -0
  73. package/coverage/rabbit-ui-kit/src/swaps-lib/utils/index.html +116 -0
  74. package/coverage/rabbit-ui-kit/src/swaps-lib/utils/swapUtils.js.html +706 -0
  75. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/arrowIcon.jsx.html +124 -0
  76. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/arrowTosca.jsx.html +127 -0
  77. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/arrowWhite.jsx.html +127 -0
  78. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/darkRectangle.jsx.html +106 -0
  79. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/determinedError.jsx.html +439 -0
  80. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/failedValidationIcon.jsx.html +202 -0
  81. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/index.html +281 -0
  82. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/infoIcon.jsx.html +133 -0
  83. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/messageIcon.jsx.html +346 -0
  84. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/noticeQuestionIcon.jsx.html +247 -0
  85. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/successfulValidationIcon.jsx.html +163 -0
  86. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/supportDialogImage.jsx.html +268 -0
  87. package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/walletIcon.jsx.html +151 -0
  88. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/AssetIcon/AssetIcon.jsx.html +256 -0
  89. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/AssetIcon/index.html +116 -0
  90. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/AssetSelection/AssetSelection.jsx.html +289 -0
  91. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/AssetSelection/index.html +116 -0
  92. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/BackgroundTitle/BackgroundTitle.jsx.html +187 -0
  93. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/BackgroundTitle/index.html +116 -0
  94. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/InformationMessage/InformationMessage.jsx.html +238 -0
  95. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/InformationMessage/index.html +116 -0
  96. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Input/Input.jsx.html +634 -0
  97. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Input/index.html +116 -0
  98. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/LoadingDots/LoadingDots.jsx.html +196 -0
  99. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/LoadingDots/index.html +116 -0
  100. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/NoticeIcon/NoticeIcon.jsx.html +277 -0
  101. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/NoticeIcon/index.html +116 -0
  102. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/QrCode/QrCode.jsx.html +199 -0
  103. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/QrCode/index.html +116 -0
  104. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/RateSelector/RateSelector.jsx.html +175 -0
  105. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/RateSelector/index.html +116 -0
  106. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/SupportChat/SupportChat.jsx.html +217 -0
  107. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/SupportChat/index.html +116 -0
  108. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Textarea/Textarea.jsx.html +529 -0
  109. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Textarea/index.html +116 -0
  110. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/TitleBox/TitleBox.jsx.html +508 -0
  111. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/TitleBox/index.html +116 -0
  112. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Tooltip/Tooltip.jsx.html +316 -0
  113. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Tooltip/index.html +116 -0
  114. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/TwoLinesOfText/LinesOfText.jsx.html +313 -0
  115. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/TwoLinesOfText/index.html +116 -0
  116. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Validation/Validation.jsx.html +202 -0
  117. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Validation/index.html +116 -0
  118. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/Button/Button.jsx.html +733 -0
  119. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/Button/index.html +116 -0
  120. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/Close/Close.jsx.html +259 -0
  121. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/Close/index.html +116 -0
  122. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/LinkButton/LinkButton.jsx.html +433 -0
  123. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/LinkButton/index.html +116 -0
  124. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/RadioButtonWithText/RadioButtonWithText.jsx.html +415 -0
  125. package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/RadioButtonWithText/index.html +116 -0
  126. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/AmountInput/AmountInput.jsx.html +1429 -0
  127. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/AmountInput/index.html +116 -0
  128. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/CoinPicker/CoinPicker.jsx.html +1474 -0
  129. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/CoinPicker/index.html +116 -0
  130. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/ColoredNotice/ColoredNotice.jsx.html +241 -0
  131. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/ColoredNotice/index.html +116 -0
  132. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/LineWithIconLink/LineWithIconLink.jsx.html +190 -0
  133. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/LineWithIconLink/index.html +116 -0
  134. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/LogoCarousel/LogoCarousel.jsx.html +307 -0
  135. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/LogoCarousel/index.html +116 -0
  136. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/SearchableCoinsList/SearchableCoinsList.jsx.html +427 -0
  137. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/SearchableCoinsList/index.html +116 -0
  138. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/TitledLineWithIconLink/TitledLineWithIconLink.jsx.html +181 -0
  139. package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/TitledLineWithIconLink/index.html +116 -0
  140. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/CoinPickerDialogStep/CoinPickerDialogStep.jsx.html +283 -0
  141. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/CoinPickerDialogStep/index.html +116 -0
  142. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/Dialog.jsx.html +1567 -0
  143. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/DialogButtons/DialogButtons.jsx.html +481 -0
  144. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/DialogButtons/index.html +116 -0
  145. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/DialogStep/DialogStep.jsx.html +1747 -0
  146. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/DialogStep/index.html +116 -0
  147. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/index.html +116 -0
  148. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/SwapForm/SwapForm.jsx.html +4375 -0
  149. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/SwapForm/index.html +116 -0
  150. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/WaitlistSubscription/WaitlistSubscription.jsx.html +559 -0
  151. package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/WaitlistSubscription/index.html +116 -0
  152. package/coverage/rabbit-ui-kit/src/ui-kit/components/templates/DeterminedErrorDialogStep/DeterminedErrorDialogStep.jsx.html +316 -0
  153. package/coverage/rabbit-ui-kit/src/ui-kit/components/templates/DeterminedErrorDialogStep/index.html +116 -0
  154. package/coverage/rabbit-ui-kit/src/ui-kit/hooks/index.html +146 -0
  155. package/coverage/rabbit-ui-kit/src/ui-kit/hooks/useCallHandlingErrors.js.html +166 -0
  156. package/coverage/rabbit-ui-kit/src/ui-kit/hooks/useIsHydrated.js.html +121 -0
  157. package/coverage/rabbit-ui-kit/src/ui-kit/hooks/useReferredState.js.html +157 -0
  158. package/coverage/rabbit-ui-kit/src/ui-kit/utils/index.html +176 -0
  159. package/coverage/rabbit-ui-kit/src/ui-kit/utils/inputValueProviders.js.html +235 -0
  160. package/coverage/rabbit-ui-kit/src/ui-kit/utils/searchCoins.js.html +259 -0
  161. package/coverage/rabbit-ui-kit/src/ui-kit/utils/textUtils.js.html +139 -0
  162. package/coverage/rabbit-ui-kit/src/ui-kit/utils/uiUtils.js.html +121 -0
  163. package/coverage/rabbit-ui-kit/src/ui-kit/utils/urlQueryUtils.js.html +271 -0
  164. package/coverage/rabbit-ui-kit/stories/atoms/BackgroundTitle.stories.jsx.html +202 -0
  165. package/coverage/rabbit-ui-kit/stories/atoms/LinesOfText.stories.jsx.html +283 -0
  166. package/coverage/rabbit-ui-kit/stories/atoms/LoadingDots.stories.jsx.html +226 -0
  167. package/coverage/rabbit-ui-kit/stories/atoms/QrCode.stories.jsx.html +175 -0
  168. package/coverage/rabbit-ui-kit/stories/atoms/RateSelector.stories.jsx.html +136 -0
  169. package/coverage/rabbit-ui-kit/stories/atoms/Validation.stories.jsx.html +178 -0
  170. package/coverage/rabbit-ui-kit/stories/atoms/buttons/Button.stories.jsx.html +883 -0
  171. package/coverage/rabbit-ui-kit/stories/atoms/buttons/Close.stories.jsx.html +211 -0
  172. package/coverage/rabbit-ui-kit/stories/atoms/buttons/LinkButton.stories.jsx.html +301 -0
  173. package/coverage/rabbit-ui-kit/stories/atoms/buttons/index.html +146 -0
  174. package/coverage/rabbit-ui-kit/stories/atoms/index.html +191 -0
  175. package/coverage/rabbit-ui-kit/stories/molecules/AmountInput.stories.jsx.html +289 -0
  176. package/coverage/rabbit-ui-kit/stories/molecules/CoinPicker.stories.jsx.html +322 -0
  177. package/coverage/rabbit-ui-kit/stories/molecules/ColoredNotice.stories.jsx.html +178 -0
  178. package/coverage/rabbit-ui-kit/stories/molecules/LineWithIconLink.stories.jsx.html +154 -0
  179. package/coverage/rabbit-ui-kit/stories/molecules/LogoCarousel.stories.jsx.html +235 -0
  180. package/coverage/rabbit-ui-kit/stories/molecules/TitledLineWithIconLink.stories.jsx.html +160 -0
  181. package/coverage/rabbit-ui-kit/stories/molecules/index.html +191 -0
  182. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/Dialog.stories.jsx.html +523 -0
  183. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogButtons/DialogButtons.stories.jsx.html +328 -0
  184. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogButtons/index.html +116 -0
  185. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogStep/DialogStep.stories.jsx.html +337 -0
  186. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogStep/index.html +116 -0
  187. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/index.html +116 -0
  188. package/coverage/rabbit-ui-kit/stories/organisms/WaitlistSubscription.stories.jsx.html +151 -0
  189. package/coverage/rabbit-ui-kit/stories/organisms/index.html +116 -0
  190. package/coverage/rabbit-ui-kit/stories/stubs/coins.jsx.html +6880 -0
  191. package/coverage/rabbit-ui-kit/stories/stubs/exampleContent.jsx.html +145 -0
  192. package/coverage/rabbit-ui-kit/stories/stubs/index.html +131 -0
  193. package/coverage/rabbit-ui-kit/stories/templates/DeterminedErrorDialogStep.stories.jsx.html +190 -0
  194. package/coverage/rabbit-ui-kit/stories/templates/index.html +116 -0
  195. package/coverage/sort-arrow-sprite.png +0 -0
  196. package/coverage/sorter.js +196 -0
  197. package/dist/global.css +197 -0
  198. package/dist/global.css.map +1 -0
  199. package/dist/index.cjs +15089 -1593
  200. package/dist/index.cjs.map +1 -1
  201. package/dist/index.css +2352 -8493
  202. package/dist/index.css.map +1 -1
  203. package/dist/index.modern.js +11801 -1298
  204. package/dist/index.modern.js.map +1 -1
  205. package/dist/index.module.js +15003 -1594
  206. package/dist/index.module.js.map +1 -1
  207. package/dist/index.umd.js +15081 -1596
  208. package/dist/index.umd.js.map +1 -1
  209. package/package.json +35 -9
  210. package/raw +1000 -0
  211. package/src/common-apis/adapters/analyticsAdapters/googleAnalyticsAdapter.js +22 -0
  212. package/src/common-apis/adapters/analyticsAdapters/metrikaAdapter.js +29 -0
  213. package/src/common-apis/adapters/analyticsAdapters/mixpanelAdapter.js +38 -0
  214. package/src/common-apis/adapters/axiosAdapter.js +35 -0
  215. package/src/common-apis/adapters/qrUtils.js +18 -0
  216. package/src/common-apis/external-apis/apiGroups.js +56 -0
  217. package/src/common-apis/external-apis/emailAPI.js +16 -0
  218. package/src/common-apis/external-apis/ipAddressProviders.js +102 -0
  219. package/src/common-apis/globalConstants.jsx +3 -0
  220. package/src/{common → common-apis}/models/coin.js +98 -7
  221. package/src/{common → common-apis/services}/fiatCurrenciesService.js +4 -12
  222. package/src/common-apis/tests/integration/external-apis/ipAddressProviders/getClientIpAddress.test.js +18 -0
  223. package/src/common-apis/tests/units/utils/amountUtils/composeRateText.test.js +152 -0
  224. package/src/{common → common-apis/utils}/amountUtils.js +100 -140
  225. package/src/{common → common-apis}/utils/cache.js +15 -41
  226. package/src/{common → common-apis/utils}/errorUtils.js +15 -0
  227. package/src/{common → common-apis}/utils/logging/logger.js +7 -13
  228. package/src/common-apis/utils/postponeExecution.js +11 -0
  229. package/src/common-apis/utils/rabbitTicker.js +24 -0
  230. package/src/index.js +91 -14
  231. package/src/robust-api-caller/cacheAndConcurrentRequestsResolver.js +525 -0
  232. package/src/robust-api-caller/cachedRobustExternalApiCallerService.js +147 -0
  233. package/src/robust-api-caller/cancelProcessing.js +29 -0
  234. package/src/robust-api-caller/concurrentCalculationsMetadataHolder.js +75 -0
  235. package/src/robust-api-caller/externalApiProvider.js +156 -0
  236. package/src/robust-api-caller/externalServicesStatsCollector.js +78 -0
  237. package/src/robust-api-caller/robustExternalAPICallerService.js +304 -0
  238. package/src/robust-api-caller/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/_performCallAttempt.test.js +533 -0
  239. package/src/robust-api-caller/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/callExternalAPI.test.js +532 -0
  240. package/src/robust-api-caller/tests/robustExternalAPICallerService/robustExternalAPICallerService/constructor.test.js +19 -0
  241. package/src/swaps-lib/external-apis/changeHeroSwapProvider.js +905 -0
  242. package/src/swaps-lib/external-apis/changeNowSwapProvider.js +853 -0
  243. package/src/swaps-lib/external-apis/exolixSwapProvider.js +619 -0
  244. package/src/swaps-lib/external-apis/goexmeSwapProvider.js +768 -0
  245. package/src/swaps-lib/external-apis/letsExchangeSwapProvider.js +527 -0
  246. package/src/swaps-lib/external-apis/retriableErrorsUtils.js +63 -0
  247. package/src/swaps-lib/external-apis/swapProvider.js +457 -25
  248. package/src/swaps-lib/external-apis/swapspaceSwapProvider.js +320 -486
  249. package/src/swaps-lib/external-apis/utils.js +26 -0
  250. package/src/swaps-lib/models/baseSwapCreationInfo.js +78 -0
  251. package/src/swaps-lib/models/existingSwap.js +101 -16
  252. package/src/swaps-lib/models/existingSwapWithFiatData.js +148 -0
  253. package/src/swaps-lib/models/partner.js +27 -0
  254. package/src/swaps-lib/models/swapProviderCoinInfo.js +84 -0
  255. package/src/swaps-lib/services/publicSwapService.js +523 -0
  256. package/src/swaps-lib/test/external-apis/changeHeroSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +155 -0
  257. package/src/swaps-lib/test/external-apis/changeHeroSwapProvider/createSwap.test.js +702 -0
  258. package/src/swaps-lib/test/external-apis/changeHeroSwapProvider/getExistingSwapsDetailsAndStatus.test.js +501 -0
  259. package/src/swaps-lib/test/external-apis/changeHeroSwapProvider/getSwapInfo.test.js +425 -0
  260. package/src/swaps-lib/test/external-apis/changeNowSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +83 -0
  261. package/src/swaps-lib/test/external-apis/changeNowSwapProvider/_providerHelpers.test.js +54 -0
  262. package/src/swaps-lib/test/external-apis/changeNowSwapProvider/_validateAddressWithProvider.test.js +49 -0
  263. package/src/swaps-lib/test/external-apis/changeNowSwapProvider/createSwap.test.js +938 -0
  264. package/src/swaps-lib/test/external-apis/changeNowSwapProvider/getExistingSwapsDetailsAndStatus.test.js +353 -0
  265. package/src/swaps-lib/test/external-apis/changeNowSwapProvider/getSwapInfo.test.js +342 -0
  266. package/src/swaps-lib/test/external-apis/exolixSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +34 -0
  267. package/src/swaps-lib/test/external-apis/exolixSwapProvider/createSwap.test.js +1081 -0
  268. package/src/swaps-lib/test/external-apis/exolixSwapProvider/getSwapInfo.test.js +611 -0
  269. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/_convertCurrencyMeta.test.js +95 -0
  270. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +75 -0
  271. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/createSwap.test.js +225 -0
  272. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/getExistingSwapsDetailsAndStatus.test.js +175 -0
  273. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/getSwapInfo.test.js +177 -0
  274. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/helpers.test.js +26 -0
  275. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/integration/PairSupport.int.test.js +69 -0
  276. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/integration/_fetchSupportedCurrenciesIfNeeded.int.test.js +307 -0
  277. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/integration/createSwap.int.test.js +335 -0
  278. package/src/swaps-lib/test/external-apis/goexmeSwapProvider/integration/getSwapInfo.int.test.js +154 -0
  279. package/src/swaps-lib/test/external-apis/swapProvider/getAllSupportedCurrencies.test.js +63 -0
  280. package/src/swaps-lib/test/external-apis/swapProvider/getDepositCurrencies.test.js +73 -0
  281. package/src/swaps-lib/test/external-apis/swapProvider/getWithdrawalCurrencies.test.js +102 -0
  282. package/src/swaps-lib/test/external-apis/swapProvider/removeProtocolNameFromCoinName.test.js +152 -0
  283. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +536 -0
  284. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/createSwap.test.js +1359 -0
  285. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getExistingSwapsDetailsAndStatus.test.js +136 -0
  286. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getSwapInfo.test.js +1743 -0
  287. package/src/swaps-lib/test/utils/swapUtils/isIpBannedProviderError.test.js +150 -0
  288. package/src/swaps-lib/test/utils/swapUtils/safeHandleRequestsLimitExceeding.test.js +80 -0
  289. package/src/swaps-lib/utils/swapUtils.js +207 -0
  290. package/{styles → src/ui-kit/assets/styles}/_functions.scss +5 -0
  291. package/{styles → src/ui-kit/assets/styles}/_mixins.scss +2 -2
  292. package/{styles → src/ui-kit/assets/styles}/_placeholder.scss +3 -3
  293. package/{styles → src/ui-kit/assets/styles}/_variables.scss +17 -15
  294. package/src/ui-kit/assets/styles/fonts/NunitoSans-Bold.ttf +0 -0
  295. package/src/ui-kit/assets/styles/fonts/NunitoSans-ExtraBold.ttf +0 -0
  296. package/src/ui-kit/assets/styles/fonts/NunitoSans-Light.ttf +0 -0
  297. package/src/ui-kit/assets/styles/fonts/NunitoSans-Regular.ttf +0 -0
  298. package/src/ui-kit/assets/styles/fonts/NunitoSans-SemiBold.ttf +0 -0
  299. package/src/ui-kit/assets/styles/global.scss +171 -0
  300. package/src/ui-kit/assets/styles/index.scss +10 -0
  301. package/src/ui-kit/assets/wrappedImages/arrowIcon.jsx +13 -0
  302. package/src/ui-kit/assets/wrappedImages/arrowTosca.jsx +14 -0
  303. package/src/ui-kit/assets/wrappedImages/arrowWhite.jsx +14 -0
  304. package/src/ui-kit/assets/wrappedImages/darkRectangle.jsx +7 -0
  305. package/src/ui-kit/assets/wrappedImages/determinedError.jsx +118 -0
  306. package/src/ui-kit/assets/wrappedImages/failedValidationIcon.jsx +39 -0
  307. package/src/ui-kit/assets/wrappedImages/infoIcon.jsx +16 -0
  308. package/src/ui-kit/assets/wrappedImages/messageIcon.jsx +87 -0
  309. package/src/ui-kit/assets/wrappedImages/noticeQuestionIcon.jsx +54 -0
  310. package/src/ui-kit/assets/wrappedImages/successfulValidationIcon.jsx +26 -0
  311. package/src/ui-kit/assets/wrappedImages/supportDialogImage.jsx +61 -0
  312. package/src/ui-kit/assets/wrappedImages/walletIcon.jsx +22 -0
  313. package/src/{components → ui-kit/components}/atoms/AssetIcon/AssetIcon.jsx +16 -14
  314. package/src/{components → ui-kit/components}/atoms/AssetIcon/asset-icon.module.scss +1 -1
  315. package/src/ui-kit/components/atoms/AssetSelection/AssetSelection.jsx +68 -0
  316. package/src/ui-kit/components/atoms/AssetSelection/asset-selection.module.scss +56 -0
  317. package/src/ui-kit/components/atoms/BackgroundTitle/BackgroundTitle.jsx +34 -0
  318. package/src/ui-kit/components/atoms/BackgroundTitle/background-title.module.scss +52 -0
  319. package/src/ui-kit/components/atoms/InformationMessage/InformationMessage.jsx +51 -0
  320. package/src/ui-kit/components/atoms/InformationMessage/information-message.module.scss +38 -0
  321. package/src/ui-kit/components/atoms/Input/Input.jsx +183 -0
  322. package/src/ui-kit/components/atoms/Input/input.module.scss +107 -0
  323. package/src/{components → ui-kit/components}/atoms/LoadingDots/LoadingDots.jsx +8 -28
  324. package/src/{components → ui-kit/components}/atoms/LoadingDots/LoadingDots.module.scss +3 -2
  325. package/src/ui-kit/components/atoms/NoticeIcon/NoticeIcon.jsx +64 -0
  326. package/src/ui-kit/components/atoms/NoticeIcon/notice-icon.module.scss +14 -0
  327. package/src/ui-kit/components/atoms/QrCode/QrCode.jsx +38 -0
  328. package/src/ui-kit/components/atoms/QrCode/qr-code.module.scss +8 -0
  329. package/src/ui-kit/components/atoms/RateSelector/RateSelector.jsx +30 -0
  330. package/src/ui-kit/components/atoms/RateSelector/rate-selector.module.scss +47 -0
  331. package/src/{components → ui-kit/components}/atoms/SupportChat/SupportChat.jsx +5 -1
  332. package/src/ui-kit/components/atoms/Textarea/Textarea.jsx +148 -0
  333. package/src/ui-kit/components/atoms/Textarea/textarea.module.scss +71 -0
  334. package/src/ui-kit/components/atoms/TitleBox/TitleBox.jsx +141 -0
  335. package/src/ui-kit/components/atoms/TitleBox/title-box.module.scss +32 -0
  336. package/src/ui-kit/components/atoms/Tooltip/Tooltip.jsx +77 -0
  337. package/src/ui-kit/components/atoms/Tooltip/tooltip.module.scss +237 -0
  338. package/src/ui-kit/components/atoms/TwoLinesOfText/LinesOfText.jsx +76 -0
  339. package/src/ui-kit/components/atoms/TwoLinesOfText/lines-of-text.module.scss +65 -0
  340. package/src/ui-kit/components/atoms/Validation/Validation.jsx +39 -0
  341. package/src/ui-kit/components/atoms/Validation/validation.module.scss +19 -0
  342. package/src/{components → ui-kit/components}/atoms/buttons/Button/Button.jsx +26 -45
  343. package/src/{components → ui-kit/components}/atoms/buttons/Button/Button.module.scss +1 -1
  344. package/src/ui-kit/components/atoms/buttons/Close/Close.jsx +58 -0
  345. package/src/ui-kit/components/atoms/buttons/Close/close.module.scss +75 -0
  346. package/src/ui-kit/components/atoms/buttons/LinkButton/LinkButton.jsx +116 -0
  347. package/src/ui-kit/components/atoms/buttons/LinkButton/link-button.module.scss +53 -0
  348. package/src/ui-kit/components/atoms/buttons/RadioButtonWithText/RadioButtonWithText.jsx +110 -0
  349. package/src/ui-kit/components/atoms/buttons/RadioButtonWithText/radio-button-with-text.module.scss +86 -0
  350. package/src/ui-kit/components/molecules/AmountInput/AmountInput.jsx +448 -0
  351. package/src/ui-kit/components/molecules/AmountInput/amount-input.module.scss +233 -0
  352. package/src/ui-kit/components/molecules/CoinPicker/CoinPicker.jsx +463 -0
  353. package/src/ui-kit/components/molecules/CoinPicker/coin-picker.module.scss +207 -0
  354. package/src/ui-kit/components/molecules/ColoredNotice/ColoredNotice.jsx +52 -0
  355. package/src/ui-kit/components/molecules/ColoredNotice/colored-notice.module.scss +36 -0
  356. package/src/ui-kit/components/molecules/LineWithIconLink/LineWithIconLink.jsx +35 -0
  357. package/src/ui-kit/components/molecules/LineWithIconLink/line-with-icon-link.module.scss +25 -0
  358. package/src/ui-kit/components/molecules/LogoCarousel/LogoCarousel.jsx +74 -0
  359. package/src/ui-kit/components/molecules/LogoCarousel/logo-carousel.module.scss +106 -0
  360. package/src/ui-kit/components/molecules/SearchableCoinsList/SearchableCoinsList.jsx +114 -0
  361. package/src/ui-kit/components/molecules/TitledLineWithIconLink/TitledLineWithIconLink.jsx +32 -0
  362. package/src/ui-kit/components/organisms/CoinPickerDialogStep/CoinPickerDialogStep.jsx +66 -0
  363. package/src/ui-kit/components/organisms/Dialog/Dialog.jsx +494 -0
  364. package/src/ui-kit/components/organisms/Dialog/DialogButtons/DialogButtons.jsx +132 -0
  365. package/src/ui-kit/components/organisms/Dialog/DialogButtons/dialog-buttons.module.scss +25 -0
  366. package/src/ui-kit/components/organisms/Dialog/DialogStep/DialogStep.jsx +554 -0
  367. package/src/ui-kit/components/organisms/Dialog/DialogStep/dialog-step.module.scss +382 -0
  368. package/src/ui-kit/components/organisms/Dialog/dialog.module.scss +226 -0
  369. package/src/ui-kit/components/organisms/SwapForm/SwapForm.jsx +1430 -0
  370. package/src/ui-kit/components/organisms/SwapForm/swap-form.module.scss +134 -0
  371. package/src/ui-kit/components/organisms/WaitlistSubscription/WaitlistSubscription.jsx +158 -0
  372. package/src/ui-kit/components/templates/DeterminedErrorDialogStep/DeterminedErrorDialogStep.jsx +77 -0
  373. package/src/ui-kit/hooks/useCallHandlingErrors.js +27 -0
  374. package/src/ui-kit/hooks/useIsHydrated.js +12 -0
  375. package/src/ui-kit/hooks/useReferredState.js +24 -0
  376. package/src/ui-kit/tests/utils/inputValueProviders/provideFormatOfFloatValueByInputString.test.js +146 -0
  377. package/src/ui-kit/tests/utils/urlQueryUtils/getQueryParameterValues.test.js +65 -0
  378. package/src/ui-kit/tests/utils/urlQueryUtils/saveQueryParameterAndValues.test.js +104 -0
  379. package/src/ui-kit/utils/inputValueProviders.js +50 -0
  380. package/src/ui-kit/utils/searchCoins.js +58 -0
  381. package/src/ui-kit/utils/textUtils.js +18 -0
  382. package/src/ui-kit/utils/uiUtils.js +12 -0
  383. package/src/ui-kit/utils/urlQueryUtils.js +62 -0
  384. package/stories/font.scss +40 -0
  385. package/stories/stubs/coins.jsx +2266 -0
  386. package/stories/stubs/exampleContent.jsx +20 -0
  387. package/styles/_global-classes.scss +0 -433
  388. package/styles/fonts/NunitoSans-Bold.ttf +0 -0
  389. package/styles/fonts/NunitoSans-ExtraBold.ttf +0 -0
  390. package/styles/fonts/NunitoSans-Light.ttf +0 -0
  391. package/styles/fonts/NunitoSans-Regular.ttf +0 -0
  392. package/styles/fonts/NunitoSans-SemiBold.ttf +0 -0
  393. package/styles/global-styles-index.scss +0 -74
  394. package/styles/index.scss +0 -33
  395. /package/src/{common → common-apis}/models/blockchain.js +0 -0
  396. /package/src/{common → common-apis}/models/protocol.js +0 -0
  397. /package/src/{common → common-apis}/utils/logging/logsStorage.js +0 -0
  398. /package/src/{common → common-apis}/utils/safeStringify.js +0 -0
  399. /package/{styles → src/ui-kit/assets/styles}/colors/_light-colors.scss +0 -0
  400. /package/{styles → src/ui-kit/assets/styles}/colors/_solid-colors.scss +0 -0
  401. /package/{styles → src/ui-kit/assets/styles}/size/_margin-size.scss +0 -0
  402. /package/{styles → src/ui-kit/assets/styles}/size/_padding-size.scss +0 -0
@@ -0,0 +1,1430 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import React, { useEffect, useState } from "react";
3
+ import PropTypes from "prop-types";
4
+
5
+ import s from "./swap-form.module.scss";
6
+
7
+ import { useReferredState } from "../../../hooks/useReferredState.js";
8
+ import { useCallHandlingErrors } from "../../../hooks/useCallHandlingErrors.js";
9
+
10
+ import { AmountUtils } from "../../../../common-apis/utils/amountUtils.js";
11
+ import { TitleBox } from "../../atoms/TitleBox/TitleBox.jsx";
12
+ import { AmountInput } from "../../molecules/AmountInput/AmountInput.jsx";
13
+ import { Validation } from "../../atoms/Validation/Validation.jsx";
14
+ import { Button } from "../../atoms/buttons/Button/Button.jsx";
15
+ import { Textarea } from "../../atoms/Textarea/Textarea.jsx";
16
+ import { Input } from "../../atoms/Input/Input.jsx";
17
+ import { RateSelector } from "../../atoms/RateSelector/RateSelector.jsx";
18
+ import { TOOLTIP_POSITIONS } from "../../atoms/Tooltip/Tooltip.jsx";
19
+ import { useIsHydrated } from "../../../hooks/useIsHydrated.js";
20
+
21
+ /**
22
+ * This is the type definition of a function used inside SwapForm to compose the URL for the hero button.
23
+ *
24
+ * @function
25
+ * @name composeConfirmButtonTo
26
+ * @param {string} [fromTicker] - Ticker symbol of the asset being sent.
27
+ * @param {string} [toTicker] - Ticker symbol of the asset being received.
28
+ * @param {string} [fromAmount] - Amount of the asset being sent.
29
+ * @return {string} Full URL or relative URL that can be used for <a href="..." />.
30
+ */
31
+
32
+ /**
33
+ * Common click handler without parameters and return value, just your logic execution.
34
+ *
35
+ * @function
36
+ * @name handleClick
37
+ * @return {void}
38
+ */
39
+
40
+ /**
41
+ * Form executes this function when swap creation info retrieval is finished successfully.
42
+ *
43
+ * @function
44
+ * @name setSwapCreationEstimation
45
+ * @param {BaseSwapCreationInfo} details - Details of the swap creation estimation.
46
+ * @return {void}
47
+ */
48
+
49
+ /**
50
+ * Error handler for unexpected errors.
51
+ *
52
+ * @function
53
+ * @name handleUnexpectedError
54
+ * @param {Error} error - The unexpected error encountered.
55
+ * @return {void}
56
+ */
57
+
58
+ /**
59
+ * Should implement the logic with rotating assets (if you want "to" to become "from" and "from" to become "to").
60
+ *
61
+ * @function
62
+ * @name rotateAssets
63
+ * @param {string} sendingAssetTicker - Ticker symbol of the asset being sent.
64
+ * @param {string} receivingAssetTicker - Ticker symbol of the asset being received.
65
+ * @return {void}
66
+ */
67
+
68
+ /**
69
+ * Error handler for standard errors that we can recognize.
70
+ *
71
+ * @function
72
+ * @name handleSwapServiceError
73
+ * @param {string} errorCode - Error code returned as "reason" from your handlers.
74
+ * @param {function} setValidationContent - Function to set the validation error message on the form.
75
+ * @param {function} setBalanceValid - Function to set the balance validity, accepts a boolean.
76
+ * @param {function} setMinimalAmountValid - Function to set the minimal amount validity, accepts a boolean.
77
+ * @param {function} setMaximumAmountValid - Function to set the maximum amount validity, accepts a boolean.
78
+ * @param {function} setIsPairSupported - Function to set the pair support status, accepts a boolean.
79
+ * @param {function} setIsSameCoins - Function to set the status if the same coins are used, accepts a boolean.
80
+ * @return {void}
81
+ */
82
+
83
+ /**
84
+ * Handler for the confirm button click. You should implement error handling inside it.
85
+ *
86
+ * @function
87
+ * @name handleConfirmButtonClick
88
+ * @param {function} resetButtonLoader - Callback for resetting the confirm button loader.
89
+ * @param {function} setValidationContent - Function to set the validation error message on the form.
90
+ * @param {function} setBalanceValid - Function to set the balance validity, accepts a boolean.
91
+ * @param {function} setMinimalAmountValid - Function to set the minimal amount validity, accepts a boolean.
92
+ * @param {function} setMaximumAmountValid - Function to set the maximum amount validity, accepts a boolean.
93
+ * @param {function} setIsPairSupported - Function to set the pair support status, accepts a boolean.
94
+ * @param {function} setIsSameCoins - Function to set the status if the same coins are used, accepts a boolean.
95
+ * @param {string} recipientAddress - The address of the recipient.
96
+ * @param {string} recipientAddressExtraId - Additional identifier for the recipient address.
97
+ * @param {string} refundAddress - The address for refund.
98
+ * @param {string} refundAddressExtraId - Additional identifier for the refund address.
99
+ * @param {string} email - Optional email address.
100
+ * @return {void}
101
+ */
102
+
103
+ /**
104
+ * Async function that retrieves swap creation info by given params.
105
+ *
106
+ * @function
107
+ * @name retrieveSwapDetails
108
+ * @param {string} sendingAssetTicker - Ticker symbol of the asset being sent.
109
+ * @param {string} receivingAssetTicker - Ticker symbol of the asset being received.
110
+ * @param {string} amount - Amount of the asset to be swapped.
111
+ * @param {boolean} [isSwapAll=false] - Indicates if the swap should use all available balance.
112
+ * @return {Promise<{
113
+ * result: false,
114
+ * reason: string,
115
+ * min: (string|null),
116
+ * max: (string|null),
117
+ * rate: (string|undefined),
118
+ * fiatMin: (number|null),
119
+ * fiatMax: (number|null)
120
+ * }|{
121
+ * result: true,
122
+ * swapCreationInfo: BaseSwapCreationInfo
123
+ * }>}
124
+ */
125
+
126
+ /**
127
+ * Async function that retrieves initial swap details for a pair like whether the pair is available, min/max swappable amounts, etc.
128
+ *
129
+ * @function
130
+ * @name retrieveInitialSwapData
131
+ * @param {string} sendingAssetTicker - Ticker symbol of the asset being sent.
132
+ * @param {string} receivingAssetTicker - Ticker symbol of the asset being received.
133
+ * @return {Promise<{
134
+ * result: true,
135
+ * min: string,
136
+ * fiatMin: (number|null),
137
+ * max: string,
138
+ * fiatMax: (number|null),
139
+ * rate: (string|null)
140
+ * }|{
141
+ * result: false,
142
+ * reason: string
143
+ * }>}
144
+ */
145
+
146
+ /**
147
+ * Function returning extraId name for asset if present.
148
+ * You must pass it if you use the form with addresses inputs.
149
+ *
150
+ * @function
151
+ * @name getExtraIdNameByTicker
152
+ * @param {string} ticker - Ticker symbol of the asset.
153
+ * @return {string|null}
154
+ */
155
+
156
+ /**
157
+ * Callback to handle isFixed flag change.
158
+ *
159
+ * @function
160
+ * @name onIsFixedChange
161
+ * @param {boolean} isFixedNewValue - new value
162
+ * @return {void}
163
+ */
164
+
165
+ /**
166
+ * Function validating addresses.
167
+ * By default, will treat any addresses as valid.
168
+ * You must pass it if you use the form with addresses inputs and want to validate addresses.
169
+ *
170
+ * @function
171
+ * @name validateAddressByTicker
172
+ * @param {string} ticker - Ticker symbol of the asset.
173
+ * @param {string} address - Address to be validated
174
+ * @param {boolean} isFixed - Is swap rate mode = fixed
175
+ * @param {function} setValidationContent - Function setting validation message text
176
+ * @return {Promise<boolean>}
177
+ */
178
+
179
+ /**
180
+ * Swap form provides basic functionality for entering to/from amounts both in crypto and fiat, switching assets,
181
+ * selecting assets, showing balance for assets. It gracefully handles unavailable fiat rates and can work
182
+ * both with and without a wallet environment (without balances).
183
+ *
184
+ * @param {object} props - Props object for SwapForm component.
185
+ * @param {string} props.sendingAssetTicker - Rabbit format of the ticker symbol for the asset being sent.
186
+ * @param {string} props.receivingAssetTicker - Rabbit format of the ticker symbol for the asset being received.
187
+ * @param {number} [props.sendingAssetDecimalCount=AmountUtils.significantDecimalCount] - Decimal count for the sending asset.
188
+ * @param {number} [props.receivingAssetDecimalCount=AmountUtils.significantDecimalCount] - Decimal count for the receiving asset.
189
+ * @param {string} props.sendingAssetTickerPrintable - Standard ticker symbol for the sending asset.
190
+ * @param {string} props.receivingAssetTickerPrintable - Standard ticker symbol for the receiving asset.
191
+ * @param {string} [props.sendingAssetProtocol] - Protocol name to be displayed in text on the change asset button.
192
+ * @param {string} [props.receivingAssetProtocol] - Protocol name to be displayed in text on the change asset button.
193
+ * @param {string} props.sendingAssetIconSrc - Source URL for the sending asset icon.
194
+ * @param {string} [props.sendingAssetProtocolIconSrc=null] - Optional source URL for the sending asset protocol icon.
195
+ * @param {string} props.receivingAssetIconSrc - Source URL for the receiving asset icon.
196
+ * @param {string} [props.receivingAssetProtocolIconSrc=null] - Optional source URL for the receiving asset protocol icon.
197
+ * @param {string} [props.fallBackAssetIconSrc=null] - Optional source URL for a fallback icon used when an icon fails to load.
198
+ * @param {string} [props.sendingAssetFeeCoinTickerPrintable] - Optional standard ticker symbol for the fee coin of the sending asset.
199
+ * @param {string} [props.sendingAssetBalance] - Balance of the sending asset.
200
+ * @param {string} [props.receivingAssetBalance] - Balance of the receiving asset.
201
+ * @param {handleClick} props.handleChangeSendingAssetClick - Function to handle clicking on the change sending asset button.
202
+ * @param {handleClick} props.handleChangeReceivingAssetClick - Function to handle clicking on the change receiving asset button.
203
+ * @param {handleConfirmButtonClick} props.handleConfirmButtonClick - Function to handle clicking on the confirm button.
204
+ * @param {composeConfirmButtonTo} props.composeConfirmButtonTo - Function to compose the URL for the confirm button.
205
+ * @param {setSwapCreationEstimation} props.setSwapCreationEstimation - Function to set the swap creation estimation.
206
+ * @param {handleUnexpectedError} props.handleUnexpectedError - Function to handle unexpected errors.
207
+ * @param {rotateAssets} props.rotateAssets - Function to rotate the assets (swap sending and receiving assets).
208
+ * @param {string} [props.preservedAmount=null] - Amount to be preserved.
209
+ * @param {handleSwapServiceError} props.handleSwapServiceError - Function to handle standard errors that we can recognize.
210
+ * @param {boolean} [props.formHasBalance] - Indicates if the form has balance information.
211
+ * @param {retrieveSwapDetails} props.retrieveSwapDetails - Function to retrieve swap details based on the given parameters.
212
+ * @param {retrieveInitialSwapData} props.retrieveInitialSwapData - Function to retrieve initial swap data for a given pair of assets.
213
+ * @param {number} props.triggerDataUpdateResetting - Number to reset interval updating the data periodically.
214
+ * @param {number} props.triggerReestimation - Number incremented to force recalculation with the current amount.
215
+ * @param {React.Ref} props.fromAssetSelectionButtonRef - Reference to the from asset selection button.
216
+ * @param {React.Ref} props.toAssetSelectionButtonRef - Reference to the to asset selection button.
217
+ * @param {number|string} [props.sendingAssetToFiatRate] - Rate for converting the sending asset to fiat.
218
+ * @param {number|string} [props.receivingAssetToFiatRate] - Rate for converting the receiving asset to fiat.
219
+ * @param {string} [props.fiatCurrencyCode] - Code for the fiat currency.
220
+ * @param {number} [props.fiatCurrencyDecimals] - Decimal places for the fiat currency.
221
+ * @param {boolean} [props.formHasFiat] - Indicates if the form supports fiat currency.
222
+ * @param {string|null} [props.termsOfUseUrl] - Terms of use URL, shown only if both terms & privacy policy passed.
223
+ * @param {string|null} [props.privacyPolicyUrl] - Privacy policy of use URL, shown only if both terms & privacy policy passed.
224
+ * @param {string|null} [props.amlPolicyUrl] - AML/KYC policy URL, optional.
225
+ * @param {object} [props.translations] - Object containing translations, default English texts will be used if omitted.
226
+ * @param {string} props.swapSeparatorIconSrc - Source URL for the swap separator icon.
227
+ * @param {boolean} props.swapButtonAlwaysActive - Setting that allows the form state to proceed to the next step regardless of validity.
228
+ * @param {getExtraIdNameByTicker} props.getExtraIdNameByTicker - Function returning extraId name for asset
229
+ * @param {validateAddressByTicker} [props.validateAddressByTicker] - Function validating address
230
+ * @param {onIsFixedChange} [props.onIsFixedChange] - callback for changed isFixed
231
+ * @return {JSX.Element} Rendered SwapForm component.
232
+ * @constructor
233
+ */
234
+ export const SwapForm = ({
235
+ sendingAssetTicker,
236
+ receivingAssetTicker,
237
+ sendingAssetDecimalCount = AmountUtils.significantDecimalCount,
238
+ receivingAssetDecimalCount = AmountUtils.significantDecimalCount,
239
+ sendingAssetTickerPrintable,
240
+ receivingAssetTickerPrintable,
241
+ sendingAssetProtocol,
242
+ receivingAssetProtocol,
243
+ sendingAssetIconSrc,
244
+ sendingAssetProtocolIconSrc = null,
245
+ receivingAssetIconSrc,
246
+ receivingAssetProtocolIconSrc = null,
247
+ fallBackAssetIconSrc = null,
248
+ sendingAssetFeeCoinTickerPrintable,
249
+ sendingAssetBalance,
250
+ receivingAssetBalance,
251
+ handleChangeSendingAssetClick,
252
+ handleChangeReceivingAssetClick,
253
+ handleConfirmButtonClick = (
254
+ resetButtonLoader,
255
+ setValidationContent,
256
+ setBalanceValid,
257
+ setMinimalAmountValid,
258
+ setMaximumAmountValid,
259
+ setIsPairSupported,
260
+ setIsSameCoins,
261
+ recipientAddress,
262
+ recipientAddressExtraId,
263
+ refundAddress,
264
+ refundAddressExtraId,
265
+ email
266
+ ) => {},
267
+ composeConfirmButtonTo = (fromTicker, toTicker, fromAmount) => "",
268
+ setSwapCreationEstimation = details => {},
269
+ handleUnexpectedError = error => {},
270
+ rotateAssets = (fromTicker, toTicker) => {},
271
+ preservedAmount = null,
272
+ handleSwapServiceError = (
273
+ errorCode,
274
+ setValidationContent,
275
+ setBalanceValid,
276
+ setMinimalAmountValid,
277
+ setMaximumAmountValid,
278
+ setIsPairSupported,
279
+ setIsSameCoins
280
+ ) => {},
281
+ formHasBalance = false,
282
+ retrieveSwapDetails = async (
283
+ sendingAssetTicker,
284
+ receivingAssetTicker,
285
+ amount,
286
+ isSwapAll = false,
287
+ isFixed = false,
288
+ amountIsToReceive = false
289
+ ) => {},
290
+ retrieveInitialSwapData = async (sendingAssetTicker, receivingAssetTicker) => {},
291
+ triggerDataUpdateResetting = 0,
292
+ triggerReestimation = 0,
293
+ fromAssetSelectionButtonRef = null,
294
+ toAssetSelectionButtonRef = null,
295
+ sendingAssetToFiatRate = null,
296
+ receivingAssetToFiatRate = null,
297
+ fiatCurrencyCode = null,
298
+ fiatCurrencyDecimals = null,
299
+ formHasFiat = true,
300
+ termsOfUseUrl = null,
301
+ privacyPolicyUrl = null,
302
+ amlPolicyUrl = null,
303
+ getExtraIdNameByTicker = ticker => null,
304
+ validateAddressByTicker = () => false,
305
+ swapSeparatorIconSrc,
306
+ swapButtonAlwaysActive = false,
307
+ onIsFixedChange = () => {},
308
+ translations = {
309
+ swapAllButtonTitles: {
310
+ enable: "Swap all",
311
+ cancel: "Cancel",
312
+ },
313
+ input: {
314
+ fiatPlaceholder: "Enter fiat amount",
315
+ balanceLoaderText: "Loading balance...",
316
+ },
317
+ consents: {
318
+ consentText: 'By clicking "Swap" you agree with Rabbit Swap\'s',
319
+ termsOfUse: "Terms of Use",
320
+ and: "and",
321
+ privacyPolicy: "Privacy Policy",
322
+ aml: "AML/KYC",
323
+ },
324
+ informationBlock: {
325
+ minimumAmount: "Minimal amount: ",
326
+ maximumAmount: "Maximum amount: ",
327
+ transactionFee: "Network fee: ",
328
+ calculatingNetworkFee: "Calculating network fee..",
329
+ loadingMinimalAmount: "Loading minimal amount..",
330
+ swapRate: "Rate: ",
331
+ calculatingSwapRates: "Calculating swap rates..",
332
+ pairNotAvailable: "Pair is not available now. Please, try again later or choose another pair.",
333
+ },
334
+ addressFields: {
335
+ addressTitle: "Recepient address",
336
+ refundAddressTitle: "Refund address",
337
+ extraIdPlaceholder: "(optional)",
338
+ refundAddressExtraIdTitle: "Refund extra ID (MEMO):",
339
+ refundAddressExtraIdNotice:
340
+ "Please check if your address requires additional identifier (sometimes called a Memo, Destination Tag, Tag, ID, Label or Note). Including this identifier is crucial when required, as omitting or misentering it can result in lost assets.",
341
+ receivingAddressExtraIdTitle: "Destination extra ID (MEMO):",
342
+ receivingAddressExtraIdNotice:
343
+ "Please check if your address requires additional identifier (sometimes called a Memo, Destination Tag, Tag, ID, Label or Note). Including this identifier is crucial when required, as omitting or misentering it can result in lost assets.",
344
+ emailTitle: "Email for notifications",
345
+ emailPlaceholder: "(optional)",
346
+ },
347
+ rateSelector: {
348
+ floatingRate: "Floating rate",
349
+ fixedRate: "Fixed rate",
350
+ },
351
+ confirmButtonText: "Swap",
352
+ },
353
+ }) => {
354
+ const DETAIL_REFRESH_INTERVAL_MS = 1.5 * 60000;
355
+ const IS_FIXED_BY_DEFAULT = false;
356
+
357
+ // Setting up an asyncronyous states, which can change during the function execution.
358
+ // This is done so that we can cancel the calculation update in case the selected asset changes.
359
+ const [sendingAssetTickerReferred, setSendingAssetTickerReferred] = useReferredState(null);
360
+ const [receivingAssetTickerReferred, setReceivingAssetTickerReferred] = useReferredState(null);
361
+
362
+ // eslint-disable-next-line react-hooks/exhaustive-deps
363
+ useEffect(() => setSendingAssetTickerReferred(sendingAssetTicker), [sendingAssetTicker]);
364
+
365
+ // eslint-disable-next-line react-hooks/exhaustive-deps
366
+ useEffect(() => setReceivingAssetTickerReferred(receivingAssetTicker), [receivingAssetTicker]);
367
+
368
+ // Updating the states below will insert the new value into the send or receive input field
369
+ const [updateSendInputTo, setUpdateSendInputTo] = useState(preservedAmount ?? null);
370
+ const [updateReceiveInputTo, setUpdateReceiveInputTo] = useState(null);
371
+
372
+ const [sendAssetAmount, setSendAssetAmount] = useReferredState(
373
+ preservedAmount == null || preservedAmount === "" ? null : preservedAmount
374
+ );
375
+ const [receiveAssetAmount, setReceiveAssetAmount] = useReferredState(null);
376
+
377
+ const [swapRate, setSwapRate] = useState();
378
+ const [minimalAmount, setMinimalAmount] = useReferredState(null);
379
+ const [maximumAmount, setMaximumAmount] = useReferredState(null);
380
+ const [validationContent, setValidationContent] = useState();
381
+
382
+ const [minimalAmountValid, setMinimalAmountValid] = useState(true); // Whether the amount is above the minimal amount
383
+ const [maximumAmountValid, setMaximumAmountValid] = useState(true);
384
+ const [isPairSupported, setIsPairSupported] = useState(true);
385
+ const [isSameCoins, setIsSameCoins] = useState(false);
386
+ const [isSwapCalculated, setIsSwapCalculated] = useState(false);
387
+ const [readyToSwap, setReadyToSwap] = useState(false); // Basically a param that enables/disables the "Next" button
388
+ // TODO: [refactoring, moderate] instead of handling preservedAmount at a lot of cases below, just
389
+ // write single useEffect setting sendAssetAmount to the=is passed value and simplify the logic below. task_id=6453251e49b04c5e88a3cc771479ffb5
390
+ const [isAmountZero, setIsAmountZero] = useState(preservedAmount == null || String(preservedAmount) === "0");
391
+ const [isLoading, setIsLoading] = useReferredState(false); // Whether the form is in the progress of loading some data (new rates, for example)
392
+ const [isFixedRate, setIsFixedRate] = useReferredState(null);
393
+ const [isLastEditedReceiving, setIsLastEditedReceiving] = useReferredState(false);
394
+ const [isFirstComponentInitialization, setIsFirstComponentInitialization] = useState(true); // Boolean "true" only until the first initialization, used to ignore some calls upon initial rendering.
395
+
396
+ const [confirmButtonTo, setConfirmButtonTo] = useState(
397
+ composeConfirmButtonTo(sendingAssetTicker, receivingAssetTicker, preservedAmount)
398
+ );
399
+
400
+ const [transactionFee, setTransactionFee] = useState();
401
+ const [balanceValid, setBalanceValid] = useState(true); // Whether the amount is less than total balance
402
+ const [isSwapAll, setIsSwapAll] = useReferredState(null);
403
+ const [swapAllButtonLoaderReSetter, setSwapAllButtonLoaderReSetter] = useState([]);
404
+
405
+ const [dataUpdateTimeoutId, setDataUpdateTimeoutId] = useReferredState(null);
406
+ const [idleDataUpdateTimeoutId, setIdleDataUpdateTimeoutId] = useReferredState(null);
407
+
408
+ const [recipientAddress, setRecipientAddress] = useReferredState("");
409
+ const [recipientAddressExtraId, setRecipientAddressExtraId] = useReferredState("");
410
+ const [isRecipientAddressValid, setIsRecipientAddressValid] = useReferredState(false);
411
+ const [isRefundAddressRequired, setIsRefundAddressRequired] = useState(false);
412
+ const [refundAddress, setRefundAddress] = useReferredState("");
413
+ const [refundAddressExtraId, setRefundAddressExtraId] = useReferredState("");
414
+ const [isRefundAddressValid, setIsRefundAddressValid] = useReferredState(false);
415
+
416
+ const [email, setEmail] = useReferredState("");
417
+ const [isEmailValid, setIsEmailValid] = useReferredState(true);
418
+
419
+ const callHandlingErrors = useCallHandlingErrors();
420
+ const isHydrated = useIsHydrated();
421
+
422
+ const recalculationDelayOnTyping = 1000;
423
+
424
+ const isAddressFieldEnabled = !formHasBalance;
425
+ const displayRateSelector = !formHasBalance;
426
+
427
+ const handleSendAssetAmountChange = amount => {
428
+ setIsLastEditedReceiving(false);
429
+ let receiveAmount = "";
430
+ if (amount != null && amount !== "" && swapRate != null) {
431
+ receiveAmount = AmountUtils.trim(BigNumber(amount).times(swapRate), receivingAssetDecimalCount);
432
+ }
433
+ setReceiveAssetAmount(receiveAmount);
434
+ setUpdateReceiveInputTo(receiveAmount);
435
+ setSendAssetAmount(amount);
436
+ };
437
+
438
+ const handleReceiveAssetAmountChange = amount => {
439
+ setReceiveAssetAmount(amount);
440
+ if (isFixedRate.current) setIsLastEditedReceiving(true);
441
+ let sendAssetAmount = "";
442
+ if (amount != null && amount !== "" && swapRate != null) {
443
+ sendAssetAmount = AmountUtils.trim(BigNumber(amount).div(swapRate), sendingAssetDecimalCount);
444
+ }
445
+ setUpdateSendInputTo(sendAssetAmount);
446
+ setSendAssetAmount(sendAssetAmount);
447
+ };
448
+
449
+ const handleMinimalAmountClick = () => {
450
+ if (!minimalAmount.current) return;
451
+
452
+ if (isLastEditedReceiving.current) {
453
+ setUpdateReceiveInputTo(minimalAmount.current?.crypto);
454
+ handleReceiveAssetAmountChange(minimalAmount.current?.crypto);
455
+ } else {
456
+ setUpdateSendInputTo(minimalAmount.current?.crypto);
457
+ handleSendAssetAmountChange(minimalAmount.current?.crypto);
458
+ }
459
+ };
460
+
461
+ const handleMaximumAmountClick = () => {
462
+ if (!maximumAmount.current) return;
463
+
464
+ if (isLastEditedReceiving.current) {
465
+ setUpdateReceiveInputTo(maximumAmount.current?.crypto);
466
+ handleReceiveAssetAmountChange(maximumAmount.current?.crypto);
467
+ } else {
468
+ setUpdateSendInputTo(maximumAmount.current?.crypto);
469
+ handleSendAssetAmountChange(maximumAmount.current?.crypto);
470
+ }
471
+ };
472
+
473
+ const handleSwapAllClick = resetButtonLoader => {
474
+ setIsSwapAll(prev => {
475
+ if (prev) {
476
+ // Setting amount inputs to empty string if we are handling the disabling of previously enabled swap all
477
+ setUpdateSendInputTo("");
478
+ setUpdateReceiveInputTo("");
479
+ setSendAssetAmount(null);
480
+ setReceiveAssetAmount(null);
481
+ }
482
+ return !prev;
483
+ });
484
+ setSwapAllButtonLoaderReSetter([resetButtonLoader]);
485
+ };
486
+
487
+ const processMinMaxAmounts = amount => {
488
+ if (amount === null) return;
489
+
490
+ setMaximumAmountValid(
491
+ !maximumAmount.current || BigNumber(amount).eq("0") || BigNumber(amount).lte(maximumAmount.current.crypto)
492
+ );
493
+ setMinimalAmountValid(
494
+ !minimalAmount.current || BigNumber(amount).eq("0") || BigNumber(amount).gte(minimalAmount.current?.crypto)
495
+ );
496
+ };
497
+
498
+ const requestDataRefresh = (amount, immediately = false, isSwapAll = false, ignoreEmptyAmount = false) => {
499
+ try {
500
+ clearTimeout(dataUpdateTimeoutId.current);
501
+
502
+ if (isSwapAll) {
503
+ loadFullEstimation(null);
504
+ return;
505
+ }
506
+
507
+ if (!amount && !ignoreEmptyAmount) {
508
+ return;
509
+ }
510
+
511
+ if (BigNumber(amount).eq("0") || amount == null || amount === "") {
512
+ if (immediately) {
513
+ loadMinimalAmountAndSwapRate(true);
514
+ } else {
515
+ setDataUpdateTimeoutId(
516
+ setTimeout(() => loadMinimalAmountAndSwapRate(true), recalculationDelayOnTyping)
517
+ );
518
+ }
519
+ } else {
520
+ if (immediately) {
521
+ loadFullEstimation(amount, preservedAmount && String(preservedAmount) !== "0" ? true : undefined);
522
+ } else {
523
+ setDataUpdateTimeoutId(setTimeout(() => loadFullEstimation(amount), recalculationDelayOnTyping));
524
+ }
525
+ }
526
+ } catch (e) {
527
+ handleUnexpectedError(e);
528
+ }
529
+ };
530
+
531
+ const setAmountLimitsAndRate = details => {
532
+ setSwapRate(details?.rate ?? null);
533
+ if (!details?.rate) {
534
+ if (isLastEditedReceiving.current) {
535
+ setUpdateSendInputTo("");
536
+ setSendAssetAmount("");
537
+ } else {
538
+ setUpdateReceiveInputTo("");
539
+ setReceiveAssetAmount("");
540
+ }
541
+ }
542
+ setMinimalAmount(details.min == null ? null : { crypto: details.min, fiat: details.fiatMin });
543
+ setMaximumAmount(details.max == null ? null : { crypto: details.max, fiat: details.fiatMax });
544
+ if (details.feeCoins != null) {
545
+ setTransactionFee({
546
+ crypto: details.feeCoins,
547
+ fiat: details.feeFiat,
548
+ });
549
+ } else {
550
+ setTransactionFee(null);
551
+ }
552
+ };
553
+
554
+ const loadFullEstimation = (amount, isForPreserved = false) => {
555
+ (async () => {
556
+ try {
557
+ const dataMemento = {
558
+ rate: swapRate,
559
+ min: minimalAmount.current?.crypto,
560
+ max: maximumAmount.current?.crypto,
561
+ feeCoins: transactionFee?.crypto,
562
+ feeFiat: transactionFee?.fiat,
563
+ };
564
+ setIsLoading(true);
565
+ setMinimalAmount(null);
566
+ setMaximumAmount(null);
567
+ setTransactionFee(null);
568
+ setValidationContent(null);
569
+ setSwapCreationEstimation(null);
570
+ setIsSameCoins(false);
571
+ setIsPairSupported(true);
572
+ setIsSwapCalculated(false);
573
+
574
+ // Saving the selected coins at the moment, so we can cancel
575
+ // the processing if they get changed during the loading.
576
+ const currentSendingAssetTicker = sendingAssetTicker;
577
+ const currentReceivingAssetTicker = receivingAssetTicker;
578
+
579
+ const response = await retrieveSwapDetails(
580
+ currentSendingAssetTicker,
581
+ currentReceivingAssetTicker,
582
+ amount,
583
+ isSwapAll.current,
584
+ isFixedRate.current ?? IS_FIXED_BY_DEFAULT,
585
+ isFixedRate.current ? isLastEditedReceiving.current : false
586
+ );
587
+
588
+ if (
589
+ currentSendingAssetTicker !== sendingAssetTickerReferred.current ||
590
+ currentReceivingAssetTicker !== receivingAssetTickerReferred.current
591
+ ) {
592
+ // Cancelling the further processing in case the
593
+ // selected coins were changed during the loading.
594
+ return;
595
+ }
596
+
597
+ if (
598
+ !isSwapAll.current &&
599
+ String(amount) !==
600
+ String(
601
+ isForPreserved && sendAssetAmount.current == null && receiveAssetAmount.current == null
602
+ ? preservedAmount
603
+ : isFixedRate.current && isLastEditedReceiving.current
604
+ ? receiveAssetAmount.current
605
+ : sendAssetAmount.current
606
+ )
607
+ ) {
608
+ // Means amount changed and we no more need to do this exact calculation
609
+ return;
610
+ }
611
+
612
+ if (response.result) {
613
+ const swapCreationInfo = response?.swapCreationInfo;
614
+
615
+ if (isSwapAll.current) {
616
+ setIsAmountZero(BigNumber("0").eq(swapCreationInfo.fromAmountCoins));
617
+ }
618
+
619
+ setUpdateSendInputTo(swapCreationInfo.fromAmountCoins);
620
+ setUpdateReceiveInputTo(swapCreationInfo.toAmountCoins);
621
+
622
+ if (isLastEditedReceiving.current) {
623
+ setSendAssetAmount(swapCreationInfo.fromAmountCoins);
624
+ } else {
625
+ setReceiveAssetAmount(swapCreationInfo.toAmountCoins);
626
+ }
627
+
628
+ setAmountLimitsAndRate(swapCreationInfo);
629
+ setSwapCreationEstimation(swapCreationInfo);
630
+ setIsRefundAddressRequired(swapCreationInfo?.isRefundAddressRequired);
631
+ processMinMaxAmounts(isSwapAll.current ? swapCreationInfo.fromAmountCoins : amount);
632
+ setIsSwapCalculated(true);
633
+ } else {
634
+ handleSwapServiceError(
635
+ response.reason,
636
+ setValidationContent,
637
+ setBalanceValid,
638
+ setMinimalAmountValid,
639
+ setMaximumAmountValid,
640
+ setIsPairSupported,
641
+ setIsSameCoins
642
+ );
643
+ if (isSwapAll.current) {
644
+ /* We disable swap all if swap all details retrieval fails and set
645
+ * previous limits and rate. We set null to avoid triggering reloading of initial data.
646
+ */
647
+ setIsSwapAll(null);
648
+ setAmountLimitsAndRate(dataMemento);
649
+ } else {
650
+ /* We set returned amount limits and rate only if the failed details retrieval is not
651
+ * for the swap All case.
652
+ */
653
+ setAmountLimitsAndRate(response);
654
+ if (isLastEditedReceiving.current) {
655
+ setSendAssetAmount("");
656
+ } else {
657
+ setReceiveAssetAmount("");
658
+ }
659
+ }
660
+ }
661
+ setIsLoading(false);
662
+ } catch (e) {
663
+ handleUnexpectedError(e);
664
+ }
665
+ })();
666
+ };
667
+
668
+ const loadMinimalAmountAndSwapRate = (isCalledForClearedInput = false) => {
669
+ (async () => {
670
+ try {
671
+ setIsLoading(true);
672
+ setMinimalAmount(null);
673
+ setMaximumAmount(null);
674
+ setSwapRate(null);
675
+ setValidationContent(null);
676
+ setIsPairSupported(true);
677
+ setIsSwapCalculated(false);
678
+
679
+ const swapData = await retrieveInitialSwapData(sendingAssetTicker, receivingAssetTicker);
680
+
681
+ if (
682
+ (isFixedRate.current && isLastEditedReceiving.current
683
+ ? receiveAssetAmount.current != null
684
+ : sendAssetAmount.current != null) &&
685
+ !isCalledForClearedInput
686
+ ) {
687
+ // Means user already entered amount after starting the form initialization
688
+ return;
689
+ }
690
+
691
+ if (swapData.result === true) {
692
+ setAmountLimitsAndRate(swapData);
693
+ } else {
694
+ handleSwapServiceError(
695
+ swapData.reason,
696
+ setValidationContent,
697
+ setBalanceValid,
698
+ setMinimalAmountValid,
699
+ setMaximumAmountValid,
700
+ setIsPairSupported,
701
+ setIsSameCoins
702
+ );
703
+ }
704
+
705
+ setIsLoading(false);
706
+ } catch (e) {
707
+ handleUnexpectedError(e);
708
+ }
709
+ })();
710
+ };
711
+
712
+ const handleChangeAssetsIconClick = e => {
713
+ callHandlingErrors(() => {
714
+ if (!isLoading.current) {
715
+ setIsSwapAll(null);
716
+ setMaximumAmountValid(true);
717
+ setMinimalAmountValid(true);
718
+
719
+ const sendAssetAmountMemento = sendAssetAmount.current;
720
+ const receiveAssetAmountMemento = receiveAssetAmount.current;
721
+
722
+ if (isLastEditedReceiving.current) {
723
+ setSendAssetAmount("");
724
+ setUpdateSendInputTo("");
725
+
726
+ setReceiveAssetAmount(sendAssetAmountMemento);
727
+ setUpdateReceiveInputTo(sendAssetAmountMemento);
728
+ } else {
729
+ setSendAssetAmount(receiveAssetAmountMemento);
730
+ setUpdateSendInputTo(receiveAssetAmountMemento);
731
+
732
+ setReceiveAssetAmount("");
733
+ setUpdateReceiveInputTo("");
734
+ }
735
+
736
+ rotateAssets(sendingAssetTicker, receivingAssetTicker);
737
+ }
738
+ }, e);
739
+ };
740
+
741
+ const handleRateModeChanged = isFixed => {
742
+ setIsFixedRate(isFixed);
743
+ requestDataRefresh(
744
+ isLastEditedReceiving.current ? receiveAssetAmount.current : sendAssetAmount.current,
745
+ true,
746
+ null,
747
+ true
748
+ );
749
+ };
750
+
751
+ useEffect(() => {
752
+ if (isSwapAll.current === true) {
753
+ requestDataRefresh(undefined, true, true);
754
+ } else if (isSwapAll.current === false) {
755
+ loadMinimalAmountAndSwapRate();
756
+ }
757
+ // eslint-disable-next-line react-hooks/exhaustive-deps
758
+ }, [isSwapAll.current]);
759
+
760
+ useEffect(() => {
761
+ onIsFixedChange(isFixedRate.current);
762
+ if (!isFixedRate.current) setIsLastEditedReceiving(false);
763
+ // eslint-disable-next-line react-hooks/exhaustive-deps
764
+ }, [isFixedRate.current]);
765
+
766
+ useEffect(() => {
767
+ if (!sendingAssetTicker || !receivingAssetTicker) return;
768
+
769
+ if (isFirstComponentInitialization) {
770
+ setIsFirstComponentInitialization(false);
771
+ return;
772
+ }
773
+
774
+ const currentAmount = isLastEditedReceiving.current ? receiveAssetAmount.current : sendAssetAmount.current;
775
+
776
+ const isCurrentAmountNotZero = currentAmount && !BigNumber("0").eq(currentAmount);
777
+
778
+ if (isCurrentAmountNotZero) {
779
+ loadFullEstimation(currentAmount);
780
+ } else {
781
+ loadMinimalAmountAndSwapRate(true);
782
+ }
783
+
784
+ // eslint-disable-next-line react-hooks/exhaustive-deps
785
+ }, [sendingAssetTicker, receivingAssetTicker]);
786
+
787
+ useEffect(() => {
788
+ if (!minimalAmountValid || isAmountZero) {
789
+ setTransactionFee(null);
790
+ }
791
+ if (isAmountZero) {
792
+ clearTimeout(dataUpdateTimeoutId.current);
793
+ }
794
+
795
+ setReadyToSwap(
796
+ swapButtonAlwaysActive ||
797
+ ((balanceValid || !formHasBalance) &&
798
+ minimalAmountValid &&
799
+ !isAmountZero &&
800
+ isSwapCalculated &&
801
+ (!isSameCoins || !formHasBalance) &&
802
+ isPairSupported &&
803
+ (!isAddressFieldEnabled || isRecipientAddressValid.current) &&
804
+ (!isRefundAddressRequired || isRefundAddressValid.current))
805
+ );
806
+ // eslint-disable-next-line react-hooks/exhaustive-deps
807
+ }, [
808
+ balanceValid,
809
+ formHasBalance,
810
+ minimalAmountValid,
811
+ isAmountZero,
812
+ isSwapCalculated,
813
+ isSameCoins,
814
+ isPairSupported,
815
+ isAddressFieldEnabled,
816
+ isRecipientAddressValid.current,
817
+ isRefundAddressRequired,
818
+ isRefundAddressValid.current,
819
+ ]);
820
+
821
+ useEffect(() => {
822
+ setIsRecipientAddressValid(false);
823
+ setRecipientAddress("");
824
+ setRecipientAddressExtraId("");
825
+ // eslint-disable-next-line react-hooks/exhaustive-deps
826
+ }, [receivingAssetTicker]);
827
+
828
+ useEffect(() => {
829
+ setIsRefundAddressValid(false);
830
+ setRefundAddress("");
831
+ setRefundAddressExtraId("");
832
+ // eslint-disable-next-line react-hooks/exhaustive-deps
833
+ }, [sendingAssetTicker]);
834
+
835
+ useEffect(() => {
836
+ (async () => {
837
+ if (!receivingAssetTicker) return;
838
+ setValidationContent("");
839
+ setIsRecipientAddressValid(
840
+ recipientAddress.current === ""
841
+ ? false
842
+ : await validateAddressByTicker(
843
+ receivingAssetTicker,
844
+ recipientAddress.current,
845
+ isFixedRate.current,
846
+ setValidationContent
847
+ )
848
+ );
849
+ })();
850
+ // eslint-disable-next-line react-hooks/exhaustive-deps
851
+ }, [recipientAddress.current, recipientAddressExtraId.current, receivingAssetTicker]);
852
+
853
+ useEffect(() => {
854
+ (async () => {
855
+ if (!sendingAssetTicker || !isRefundAddressRequired) return;
856
+ setValidationContent("");
857
+ setIsRefundAddressValid(
858
+ refundAddress.current === ""
859
+ ? false
860
+ : await validateAddressByTicker(
861
+ sendingAssetTicker,
862
+ refundAddress.current,
863
+ isFixedRate.current,
864
+ setValidationContent
865
+ )
866
+ );
867
+ })();
868
+ // eslint-disable-next-line react-hooks/exhaustive-deps
869
+ }, [refundAddress.current, refundAddressExtraId.current, sendingAssetTicker, isRefundAddressRequired]);
870
+
871
+ useEffect(() => {
872
+ // Email validation - optional field, so valid if empty or valid email format
873
+ const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
874
+ setIsEmailValid(email.current === "" || emailRegex.test(email.current));
875
+ // eslint-disable-next-line react-hooks/exhaustive-deps
876
+ }, [email.current]);
877
+
878
+ useEffect(() => {
879
+ // Here we set up auto recalculations for the swap details if the form is ready to swap but is idle for some time
880
+ let timeoutId = null;
881
+ if (readyToSwap) {
882
+ timeoutId = setTimeout(
883
+ () =>
884
+ requestDataRefresh(
885
+ isLastEditedReceiving.current
886
+ ? receiveAssetAmount.current
887
+ : sendAssetAmount.current ?? preservedAmount,
888
+ true
889
+ ),
890
+ DETAIL_REFRESH_INTERVAL_MS
891
+ );
892
+ setIdleDataUpdateTimeoutId(timeoutId);
893
+ } else {
894
+ clearTimeout(idleDataUpdateTimeoutId.current);
895
+ setIdleDataUpdateTimeoutId(null);
896
+ }
897
+ return () => {
898
+ timeoutId != null && clearTimeout(timeoutId);
899
+ };
900
+ // eslint-disable-next-line react-hooks/exhaustive-deps
901
+ }, [readyToSwap]);
902
+
903
+ useEffect(() => {
904
+ if (!triggerReestimation) return;
905
+
906
+ const currentAmount = isLastEditedReceiving.current ? receiveAssetAmount.current : sendAssetAmount.current;
907
+ handleAmountChange(currentAmount, true, !!isSwapAll.current, true);
908
+ // eslint-disable-next-line react-hooks/exhaustive-deps
909
+ }, [triggerReestimation]);
910
+
911
+ // TODO: [refactoring, critical] this code looks like a hack related to task_id=6e328d39063142b7b9fa01d497e616da
912
+ useEffect(() => {
913
+ if (triggerDataUpdateResetting) {
914
+ clearTimeout(dataUpdateTimeoutId.current);
915
+ setDataUpdateTimeoutId(null);
916
+
917
+ clearTimeout(idleDataUpdateTimeoutId.current);
918
+ setIdleDataUpdateTimeoutId(null);
919
+ }
920
+ // eslint-disable-next-line react-hooks/exhaustive-deps
921
+ }, [triggerDataUpdateResetting]);
922
+
923
+ // Resets the passed "set value to" param to null, so it can be used multiple times with any value
924
+ useEffect(() => {
925
+ if (!!updateSendInputTo) setUpdateSendInputTo(null);
926
+ if (!!updateReceiveInputTo) setUpdateReceiveInputTo(null);
927
+ // eslint-disable-next-line react-hooks/exhaustive-deps
928
+ }, [updateSendInputTo, updateReceiveInputTo]);
929
+
930
+ useEffect(() => {
931
+ if (
932
+ swapRate != null &&
933
+ (isLastEditedReceiving.current ? receiveAssetAmount.current : sendAssetAmount.current) != null
934
+ ) {
935
+ if (isLastEditedReceiving.current) {
936
+ setUpdateSendInputTo(
937
+ AmountUtils.trim(BigNumber(receiveAssetAmount.current).div(swapRate), sendingAssetDecimalCount)
938
+ );
939
+ } else {
940
+ setUpdateReceiveInputTo(
941
+ AmountUtils.trim(BigNumber(sendAssetAmount.current).times(swapRate), receivingAssetDecimalCount)
942
+ );
943
+ }
944
+ }
945
+ // eslint-disable-next-line react-hooks/exhaustive-deps
946
+ }, [swapRate]);
947
+
948
+ useEffect(() => {
949
+ if (isLoading.current === false && swapAllButtonLoaderReSetter?.length) {
950
+ swapAllButtonLoaderReSetter[0]();
951
+ setSwapAllButtonLoaderReSetter([]);
952
+ }
953
+ // eslint-disable-next-line react-hooks/exhaustive-deps
954
+ }, [isLoading.current, swapAllButtonLoaderReSetter]);
955
+
956
+ const handleAmountChange = (amount, immediately = false, isSwapAll = false, ignoreEmptyAmount = false) => {
957
+ requestDataRefresh(amount, immediately, isSwapAll, ignoreEmptyAmount);
958
+ processMinMaxAmounts(amount);
959
+ setIsAmountZero(BigNumber("0").eq(amount));
960
+ setIsSwapCalculated(false);
961
+ };
962
+
963
+ useEffect(() => {
964
+ if (isLastEditedReceiving.current)
965
+ handleAmountChange(receiveAssetAmount.current === "" ? "0" : receiveAssetAmount.current);
966
+ }, [receiveAssetAmount.current]);
967
+
968
+ useEffect(() => {
969
+ if (!isLastEditedReceiving.current)
970
+ handleAmountChange(sendAssetAmount.current === "" ? "0" : sendAssetAmount.current);
971
+ }, [sendAssetAmount.current]);
972
+
973
+ const recipientAddressExtraIdName = getExtraIdNameByTicker(receivingAssetTicker);
974
+ const refundAddressExtraIdName = getExtraIdNameByTicker(sendingAssetTicker);
975
+
976
+ return (
977
+ <div className={s["swap-form"]}>
978
+ <TitleBox
979
+ linkButtonClick={
980
+ BigNumber(sendingAssetBalance?.assetAmount).eq(0)
981
+ ? null
982
+ : resetButtonLoader => handleSwapAllClick(resetButtonLoader)
983
+ }
984
+ linkText={
985
+ !formHasBalance
986
+ ? ""
987
+ : isSwapAll.current
988
+ ? translations.swapAllButtonTitles.cancel
989
+ : translations.swapAllButtonTitles.enable
990
+ }
991
+ linkButtonLoader={true}
992
+ isLinkButtonDisabled={
993
+ isLoading.current ||
994
+ sendingAssetTicker === receivingAssetTicker ||
995
+ BigNumber(sendingAssetBalance?.assetAmount).eq(0)
996
+ }
997
+ >
998
+ {displayRateSelector ? (
999
+ <div className={s["swap-form-rate-selector"]}>
1000
+ <RateSelector
1001
+ isFixed={isFixedRate.current ?? IS_FIXED_BY_DEFAULT}
1002
+ setIsFixed={handleRateModeChanged}
1003
+ translations={translations.rateSelector}
1004
+ />
1005
+ </div>
1006
+ ) : (
1007
+ ""
1008
+ )}
1009
+
1010
+ <div className={s["swap-form-inputs"]}>
1011
+ <AmountInput
1012
+ ticker={sendingAssetTicker}
1013
+ tickerPrintable={sendingAssetTickerPrintable}
1014
+ assetDecimalPlaces={sendingAssetDecimalCount}
1015
+ assetBalance={sendingAssetBalance}
1016
+ assetIconSrc={sendingAssetIconSrc}
1017
+ assetIconProtocolSrc={sendingAssetProtocolIconSrc}
1018
+ fallbackAssetIconSrc={fallBackAssetIconSrc}
1019
+ disabled={isSwapAll.current || sendingAssetTicker === null || receivingAssetTicker === null}
1020
+ handleCoinAmountChange={handleSendAssetAmountChange}
1021
+ handleChangeAssetClick={handleChangeSendingAssetClick}
1022
+ handleBalanceValidationChange={isValid => setBalanceValid(!isValid)}
1023
+ updateAssetInputTo={updateSendInputTo}
1024
+ showBalance={formHasBalance}
1025
+ showBalanceValidation={formHasBalance}
1026
+ showChangeAssetButton
1027
+ changeAssetButtonProtocol={sendingAssetProtocol}
1028
+ upperFormPosition
1029
+ errorEncountered={
1030
+ !isLastEditedReceiving.current && (!minimalAmountValid || !maximumAmountValid)
1031
+ }
1032
+ ref={fromAssetSelectionButtonRef}
1033
+ isLoading={isLastEditedReceiving.current ? isLoading.current : false}
1034
+ cryptoAssetToFiatRate={sendingAssetToFiatRate}
1035
+ fiatCurrencyCode={
1036
+ formHasFiat && (isLoading.current || sendingAssetToFiatRate != null)
1037
+ ? fiatCurrencyCode
1038
+ : null
1039
+ }
1040
+ fiatCurrencyDecimals={fiatCurrencyDecimals}
1041
+ balanceLoaderText={translations.input.balanceLoaderText}
1042
+ fiatInputPlaceholderText={translations.input.fiatPlaceholder}
1043
+ />
1044
+ <div
1045
+ className={
1046
+ s["swap-form-inputs-separator"] +
1047
+ " " +
1048
+ (isLoading.current || sendingAssetTicker === null || receivingAssetTicker === null
1049
+ ? s["disabled"]
1050
+ : "")
1051
+ }
1052
+ >
1053
+ <img
1054
+ src={swapSeparatorIconSrc}
1055
+ alt="swap icon"
1056
+ draggable={false}
1057
+ onClick={e => callHandlingErrors(handleChangeAssetsIconClick, e)}
1058
+ loading="lazy"
1059
+ />
1060
+ </div>
1061
+ <AmountInput
1062
+ ticker={receivingAssetTicker}
1063
+ tickerPrintable={receivingAssetTickerPrintable}
1064
+ assetDecimalPlaces={receivingAssetDecimalCount}
1065
+ assetBalance={receivingAssetBalance}
1066
+ assetIconSrc={receivingAssetIconSrc}
1067
+ assetIconProtocolSrc={receivingAssetProtocolIconSrc}
1068
+ fallbackAssetIconSrc={fallBackAssetIconSrc}
1069
+ disabled={isSwapAll.current || sendingAssetTicker === null || receivingAssetTicker === null}
1070
+ locked
1071
+ handleCoinAmountChange={handleReceiveAssetAmountChange}
1072
+ handleChangeAssetClick={handleChangeReceivingAssetClick}
1073
+ updateAssetInputTo={updateReceiveInputTo}
1074
+ showChangeAssetButton
1075
+ changeAssetButtonProtocol={receivingAssetProtocol}
1076
+ showBalance={formHasBalance}
1077
+ lowerFormPosition
1078
+ errorEncountered={isLastEditedReceiving.current && (!minimalAmountValid || !maximumAmountValid)}
1079
+ estimateAmount={!isFixedRate.current}
1080
+ ref={toAssetSelectionButtonRef}
1081
+ isLoading={isLastEditedReceiving.current ? false : isLoading.current}
1082
+ cryptoAssetToFiatRate={receivingAssetToFiatRate}
1083
+ fiatCurrencyCode={
1084
+ formHasFiat && (isLoading.current || receivingAssetToFiatRate != null)
1085
+ ? fiatCurrencyCode
1086
+ : null
1087
+ }
1088
+ fiatCurrencyDecimals={fiatCurrencyDecimals}
1089
+ balanceLoaderText={translations.input.balanceLoaderText}
1090
+ fiatInputPlaceholderText={translations.input.fiatPlaceholder}
1091
+ />
1092
+ </div>
1093
+ <div className={s["swap-form-information-field"]}>
1094
+ {/* TODO: [refactoring, moderate] Add flags calculation for each message to avoid this ugly cumbersome implicit unclear logic of message displaying. task_id=8bc31dbcd94d46a598346e8bfb505971 */}
1095
+ <p>
1096
+ {!isPairSupported ? (
1097
+ translations.informationBlock.pairNotAvailable
1098
+ ) : transactionFee && minimalAmountValid ? (
1099
+ <>
1100
+ {translations.informationBlock.transactionFee}
1101
+ <span>
1102
+ {AmountUtils.crypto(transactionFee?.crypto, sendingAssetFeeCoinTickerPrintable)}
1103
+ </span>
1104
+ {transactionFee?.fiat != null && transactionFee?.fiat !== "" ? (
1105
+ <span className={"semi-transparent"}>
1106
+ {" ~ " + AmountUtils.fiat(transactionFee?.fiat, fiatCurrencyCode)}
1107
+ </span>
1108
+ ) : (
1109
+ ""
1110
+ )}
1111
+ </>
1112
+ ) : !isLoading.current && (isSwapCalculated || (!minimalAmount.current && swapRate)) ? (
1113
+ <>
1114
+ {translations.informationBlock.swapRate}
1115
+ <span>
1116
+ {AmountUtils.composeRateText(
1117
+ sendingAssetTickerPrintable,
1118
+ receivingAssetTickerPrintable,
1119
+ swapRate,
1120
+ receivingAssetDecimalCount,
1121
+ isFixedRate.current ?? IS_FIXED_BY_DEFAULT
1122
+ )}
1123
+ </span>
1124
+ </>
1125
+ ) : minimalAmount.current || maximumAmount.current ? (
1126
+ !maximumAmountValid && maximumAmount.current != null ? (
1127
+ <>
1128
+ {translations.informationBlock.maximumAmount}
1129
+ <span
1130
+ className={s["interactable"] + " " + s["red"]}
1131
+ onClick={
1132
+ isLoading.current
1133
+ ? () => {}
1134
+ : e => callHandlingErrors(handleMaximumAmountClick, e)
1135
+ }
1136
+ >
1137
+ {AmountUtils.crypto(
1138
+ maximumAmount.current?.crypto,
1139
+ isLastEditedReceiving.current
1140
+ ? receivingAssetTickerPrintable
1141
+ : sendingAssetTickerPrintable
1142
+ )}
1143
+ </span>
1144
+ {maximumAmount.current?.fiat != null && maximumAmount.current?.fiat !== "" ? (
1145
+ <span className={"semi-transparent"}>
1146
+ {" ~ " + AmountUtils.fiat(maximumAmount.current.fiat, fiatCurrencyCode)}
1147
+ </span>
1148
+ ) : (
1149
+ ""
1150
+ )}
1151
+ </>
1152
+ ) : !minimalAmount.current ? (
1153
+ ""
1154
+ ) : (
1155
+ <>
1156
+ {translations.informationBlock.minimumAmount}
1157
+ <span
1158
+ className={s["interactable"] + " " + (!minimalAmountValid ? s["red"] : "")}
1159
+ onClick={
1160
+ isLoading.current
1161
+ ? () => {}
1162
+ : e => callHandlingErrors(handleMinimalAmountClick, e)
1163
+ }
1164
+ >
1165
+ {AmountUtils.crypto(
1166
+ minimalAmount.current.crypto,
1167
+ isLastEditedReceiving.current
1168
+ ? receivingAssetTickerPrintable
1169
+ : sendingAssetTickerPrintable
1170
+ )}
1171
+ </span>
1172
+ {minimalAmount.current?.fiat != null && minimalAmount.current.fiat !== "" ? (
1173
+ <span className={"semi-transparent"}>
1174
+ {" ~ " + AmountUtils.fiat(minimalAmount.current.fiat, fiatCurrencyCode)}
1175
+ </span>
1176
+ ) : (
1177
+ ""
1178
+ )}
1179
+ </>
1180
+ )
1181
+ ) : isLoading.current ? (
1182
+ sendAssetAmount.current || receiveAssetAmount.current || isSwapAll.current ? (
1183
+ translations.informationBlock[
1184
+ formHasBalance ? "calculatingNetworkFee" : "calculatingSwapRates"
1185
+ ]
1186
+ ) : (
1187
+ translations.informationBlock.loadingMinimalAmount
1188
+ )
1189
+ ) : (
1190
+ translations?.informationBlock?.enterAmount
1191
+ )}
1192
+ </p>
1193
+ </div>
1194
+
1195
+ {isAddressFieldEnabled ? (
1196
+ <div className={s["swap-form-address-field"]}>
1197
+ <TitleBox title={translations.addressFields.addressTitle}>
1198
+ <Textarea
1199
+ type={"text"}
1200
+ onChange={e => setRecipientAddress(e.target.value)}
1201
+ value={recipientAddress.current}
1202
+ adaptiveHeight={true}
1203
+ errorEncountered={recipientAddress.current !== "" && !isRecipientAddressValid.current}
1204
+ />
1205
+ </TitleBox>
1206
+ {isHydrated && recipientAddressExtraIdName ? (
1207
+ <TitleBox
1208
+ title={translations.addressFields.receivingAddressExtraIdTitle}
1209
+ titleNoticeText={translations.addressFields.receivingAddressExtraIdNotice}
1210
+ titleNoticePosition={TOOLTIP_POSITIONS.TOP_LEFT}
1211
+ >
1212
+ <Textarea
1213
+ type={"text"}
1214
+ onChange={e => setRecipientAddressExtraId(e.target.value)}
1215
+ value={recipientAddressExtraId.current}
1216
+ adaptiveHeight={true}
1217
+ placeholder={translations.addressFields.extraIdPlaceholder}
1218
+ />
1219
+ </TitleBox>
1220
+ ) : null}
1221
+ {isHydrated && isRefundAddressRequired ? (
1222
+ <>
1223
+ <TitleBox title={translations.addressFields.refundAddressTitle}>
1224
+ <Textarea
1225
+ type={"text"}
1226
+ onChange={e => setRefundAddress(e.target.value)}
1227
+ value={refundAddress.current}
1228
+ adaptiveHeight={true}
1229
+ errorEncountered={refundAddress.current !== "" && !isRefundAddressValid.current}
1230
+ />
1231
+ </TitleBox>
1232
+ {refundAddressExtraIdName ? (
1233
+ <TitleBox
1234
+ title={translations.addressFields.refundAddressExtraIdTitle}
1235
+ titleNoticeText={translations.addressFields.refundAddressExtraIdNotice}
1236
+ titleNoticePosition={TOOLTIP_POSITIONS.TOP_LEFT}
1237
+ >
1238
+ <Textarea
1239
+ type={"text"}
1240
+ onChange={e => setRefundAddressExtraId(e.target.value)}
1241
+ value={refundAddressExtraId.current}
1242
+ adaptiveHeight={true}
1243
+ placeholder={translations.addressFields.extraIdPlaceholder}
1244
+ />
1245
+ </TitleBox>
1246
+ ) : null}
1247
+ </>
1248
+ ) : null}
1249
+ </div>
1250
+ ) : null}
1251
+
1252
+ <div className={s["swap-form-address-field"]}>
1253
+ <TitleBox title={translations.addressFields?.emailTitle || "Email (optional)"}>
1254
+ <Input
1255
+ type="email"
1256
+ onChange={e => setEmail(e.target.value)}
1257
+ value={email.current}
1258
+ placeholder={translations.addressFields?.emailPlaceholder}
1259
+ errorEncountered={email.current !== "" && !isEmailValid.current}
1260
+ />
1261
+ </TitleBox>
1262
+ </div>
1263
+
1264
+ {validationContent ? (
1265
+ <div className={s["swap-form-validation-text"]}>
1266
+ <Validation text={validationContent} />
1267
+ </div>
1268
+ ) : (
1269
+ ""
1270
+ )}
1271
+ <div className={s["swap-form-button-container"]}>
1272
+ {!termsOfUseUrl || !privacyPolicyUrl ? null : (
1273
+ <p className={s["swap-form-button-container-consent-text"]}>
1274
+ {translations.consents.consentText + " "}
1275
+ <a href={termsOfUseUrl} className={s["swap-form-button-container-consent-text-link"]}>
1276
+ {translations.consents.termsOfUse}
1277
+ </a>
1278
+ {", "}
1279
+ <a href={privacyPolicyUrl} className={s["swap-form-button-container-consent-text-link"]}>
1280
+ {translations.consents.privacyPolicy}
1281
+ </a>
1282
+ {amlPolicyUrl ? (
1283
+ <>
1284
+ {" " + translations.consents.and + " "}
1285
+ <a
1286
+ href={amlPolicyUrl}
1287
+ className={s["swap-form-button-container-consent-text-link"]}
1288
+ >
1289
+ {translations.consents.aml}
1290
+ </a>
1291
+ </>
1292
+ ) : null}
1293
+ .
1294
+ </p>
1295
+ )}
1296
+ <Button
1297
+ size="lg"
1298
+ mode="primary"
1299
+ content={translations.confirmButtonText}
1300
+ onClick={resetButtonLoader =>
1301
+ handleConfirmButtonClick(
1302
+ resetButtonLoader,
1303
+ setValidationContent,
1304
+ setBalanceValid,
1305
+ setMinimalAmountValid,
1306
+ setMaximumAmountValid,
1307
+ setIsPairSupported,
1308
+ setIsSameCoins,
1309
+ recipientAddress.current,
1310
+ recipientAddressExtraId.current,
1311
+ refundAddress.current,
1312
+ refundAddressExtraId.current,
1313
+ email.current,
1314
+ isLastEditedReceiving.current
1315
+ )
1316
+ }
1317
+ fullWidthOnMobiles
1318
+ isDisabled={!readyToSwap}
1319
+ to={formHasBalance ? "" : confirmButtonTo}
1320
+ loader
1321
+ handleError={callHandlingErrors}
1322
+ />
1323
+ </div>
1324
+ </TitleBox>
1325
+ </div>
1326
+ );
1327
+ };
1328
+
1329
+ SwapForm.propTypes = {
1330
+ sendingAssetTicker: PropTypes.string.isRequired,
1331
+ receivingAssetTicker: PropTypes.string.isRequired,
1332
+ sendingAssetDecimalCount: PropTypes.number,
1333
+ receivingAssetDecimalCount: PropTypes.number,
1334
+ sendingAssetTickerPrintable: PropTypes.string.isRequired,
1335
+ receivingAssetTickerPrintable: PropTypes.string.isRequired,
1336
+ sendingAssetProtocol: PropTypes.string,
1337
+ receivingAssetProtocol: PropTypes.string,
1338
+ sendingAssetIconSrc: PropTypes.string.isRequired,
1339
+ sendingAssetProtocolIconSrc: PropTypes.string,
1340
+ receivingAssetIconSrc: PropTypes.string.isRequired,
1341
+ receivingAssetProtocolIconSrc: PropTypes.string,
1342
+ fallBackAssetIconSrc: PropTypes.string,
1343
+ sendingAssetFeeCoinTickerPrintable: PropTypes.string,
1344
+ sendingAssetBalance: PropTypes.string,
1345
+ receivingAssetBalance: PropTypes.string,
1346
+ handleChangeSendingAssetClick: PropTypes.func.isRequired,
1347
+ handleChangeReceivingAssetClick: PropTypes.func.isRequired,
1348
+ handleConfirmButtonClick: PropTypes.func,
1349
+ composeConfirmButtonTo: PropTypes.func,
1350
+ setSwapCreationEstimation: PropTypes.func,
1351
+ handleUnexpectedError: PropTypes.func,
1352
+ rotateAssets: PropTypes.func,
1353
+ preservedAmount: PropTypes.string,
1354
+ handleSwapServiceError: PropTypes.func.isRequired,
1355
+ formHasBalance: PropTypes.bool,
1356
+ retrieveSwapDetails: PropTypes.func.isRequired,
1357
+ retrieveInitialSwapData: PropTypes.func.isRequired,
1358
+ triggerDataUpdateResetting: PropTypes.number,
1359
+ triggerReestimation: PropTypes.number,
1360
+ fromAssetSelectionButtonRef: PropTypes.any,
1361
+ toAssetSelectionButtonRef: PropTypes.any,
1362
+ sendingAssetToFiatRate: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
1363
+ receivingAssetToFiatRate: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
1364
+ fiatCurrencyCode: PropTypes.string,
1365
+ fiatCurrencyDecimals: PropTypes.number,
1366
+ formHasFiat: PropTypes.bool,
1367
+ termsOfUseUrl: PropTypes.string,
1368
+ privacyPolicyUrl: PropTypes.string,
1369
+ amlPolicyUrl: PropTypes.string,
1370
+ getExtraIdNameByTicker: PropTypes.func,
1371
+ translations: PropTypes.object,
1372
+ validateAddressByTicker: PropTypes.func,
1373
+ swapSeparatorIconSrc: PropTypes.string.isRequired,
1374
+ swapButtonAlwaysActive: PropTypes.bool,
1375
+ onIsFixedChange: PropTypes.func,
1376
+ };
1377
+
1378
+ SwapForm.defaultProps = {
1379
+ sendingAssetDecimalCount: AmountUtils.significantDecimalCount,
1380
+ receivingAssetDecimalCount: AmountUtils.significantDecimalCount,
1381
+ sendingAssetProtocolIconSrc: null,
1382
+ receivingAssetProtocolIconSrc: null,
1383
+ fallBackAssetIconSrc: null,
1384
+ handleConfirmButtonClick: (
1385
+ resetButtonLoader,
1386
+ setValidationContent,
1387
+ setBalanceValid,
1388
+ setMinimalAmountValid,
1389
+ setMaximumAmountValid,
1390
+ setIsPairSupported,
1391
+ setIsSameCoins,
1392
+ recipientAddress,
1393
+ recipientAddressExtraId,
1394
+ refundAddress,
1395
+ refundAddressExtraId,
1396
+ email
1397
+ ) => {},
1398
+ composeConfirmButtonTo: (fromTicker, toTicker, fromAmount) => "",
1399
+ setSwapCreationEstimation: details => {},
1400
+ handleUnexpectedError: error => {},
1401
+ rotateAssets: (fromTicker, toTicker) => {},
1402
+ preservedAmount: null,
1403
+ handleSwapServiceError: (
1404
+ errorCode,
1405
+ setValidationContent,
1406
+ setBalanceValid,
1407
+ setMinimalAmountValid,
1408
+ setMaximumAmountValid,
1409
+ setIsPairSupported,
1410
+ setIsSameCoins
1411
+ ) => {},
1412
+ retrieveSwapDetails: async (sendingAssetTicker, receivingAssetTicker, amount, isSwapAll = false) => {},
1413
+ retrieveInitialSwapData: async (sendingAssetTicker, receivingAssetTicker) => {},
1414
+ triggerDataUpdateResetting: 0,
1415
+ triggerReestimation: 0,
1416
+ fromAssetSelectionButtonRef: null,
1417
+ toAssetSelectionButtonRef: null,
1418
+ sendingAssetToFiatRate: null,
1419
+ receivingAssetToFiatRate: null,
1420
+ fiatCurrencyCode: null,
1421
+ fiatCurrencyDecimals: null,
1422
+ formHasFiat: true,
1423
+ termsOfUseUrl: null,
1424
+ privacyPolicyUrl: null,
1425
+ amlPolicyUrl: null,
1426
+ getExtraIdNameByTicker: ticker => null,
1427
+ validateAddressByTicker: ticker => false,
1428
+ swapButtonAlwaysActive: false,
1429
+ onIsFixedChange: () => {},
1430
+ };