@rabbitio/ui-kit 1.0.0-beta.4 → 1.0.0-beta.40

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 (55) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/README.md +23 -16
  3. package/dist/index.cjs +5336 -9
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +4480 -1635
  6. package/dist/index.css.map +1 -1
  7. package/dist/index.modern.js +3766 -11
  8. package/dist/index.modern.js.map +1 -1
  9. package/dist/index.module.js +5298 -11
  10. package/dist/index.module.js.map +1 -1
  11. package/dist/index.umd.js +5335 -12
  12. package/dist/index.umd.js.map +1 -1
  13. package/index.js +1 -1
  14. package/package.json +16 -22
  15. package/src/common/adapters/axiosAdapter.js +35 -0
  16. package/src/common/amountUtils.js +434 -0
  17. package/src/common/errorUtils.js +42 -0
  18. package/src/common/external-apis/apiGroups.js +55 -0
  19. package/src/common/fiatCurrenciesService.js +161 -0
  20. package/src/common/models/blockchain.js +10 -0
  21. package/src/common/models/coin.js +157 -0
  22. package/src/common/models/protocol.js +5 -0
  23. package/src/common/utils/cache.js +268 -0
  24. package/src/common/utils/emailAPI.js +18 -0
  25. package/src/common/utils/logging/logger.js +48 -0
  26. package/src/common/utils/logging/logsStorage.js +61 -0
  27. package/src/common/utils/postponeExecution.js +11 -0
  28. package/src/common/utils/safeStringify.js +50 -0
  29. package/src/components/atoms/AssetIcon/AssetIcon.jsx +55 -0
  30. package/src/components/atoms/AssetIcon/asset-icon.module.scss +42 -0
  31. package/{stories → src/components}/atoms/LoadingDots/LoadingDots.module.scss +1 -1
  32. package/src/components/atoms/SupportChat/SupportChat.jsx +48 -0
  33. package/{stories → src/components}/atoms/buttons/Button/Button.jsx +11 -7
  34. package/{stories → src/components}/atoms/buttons/Button/Button.module.scss +6 -1
  35. package/src/components/hooks/useCallHandlingErrors.js +26 -0
  36. package/src/components/hooks/useReferredState.js +24 -0
  37. package/src/components/utils/uiUtils.js +14 -0
  38. package/src/components/utils/urlQueryUtils.js +87 -0
  39. package/src/index.js +52 -0
  40. package/src/robustExteranlApiCallerService/cacheAndConcurrentRequestsResolver.js +559 -0
  41. package/src/robustExteranlApiCallerService/cachedRobustExternalApiCallerService.js +188 -0
  42. package/src/robustExteranlApiCallerService/cancelProcessing.js +29 -0
  43. package/src/robustExteranlApiCallerService/concurrentCalculationsMetadataHolder.js +103 -0
  44. package/src/robustExteranlApiCallerService/externalApiProvider.js +156 -0
  45. package/src/robustExteranlApiCallerService/externalServicesStatsCollector.js +82 -0
  46. package/src/robustExteranlApiCallerService/robustExternalAPICallerService.js +386 -0
  47. package/src/swaps-lib/external-apis/swapProvider.js +201 -0
  48. package/src/swaps-lib/external-apis/swapspaceSwapProvider.js +877 -0
  49. package/src/swaps-lib/models/baseSwapCreationInfo.js +40 -0
  50. package/src/swaps-lib/models/existingSwap.js +70 -0
  51. package/src/swaps-lib/models/existingSwapWithFiatData.js +130 -0
  52. package/src/swaps-lib/services/publicSwapService.js +674 -0
  53. package/src/swaps-lib/utils/swapUtils.js +219 -0
  54. package/stories/index.js +0 -2
  55. /package/{stories → src/components}/atoms/LoadingDots/LoadingDots.jsx +0 -0
@@ -1,5 +1,9 @@
1
- import React, { useState, useRef, useEffect } from 'react';
2
- import { Link } from 'react-router-dom';
1
+ import React, { useState, useRef, useEffect, useCallback } from 'react';
2
+ import { BigNumber } from 'bignumber.js';
3
+ import axios from 'axios';
4
+ import { v4 } from 'uuid';
5
+ import Hashes from 'jshashes';
6
+ import EventBusInstance from 'eventbusjs';
3
7
 
4
8
  function createCommonjsModule(fn) {
5
9
  var module = { exports: {} };
@@ -1152,9 +1156,9 @@ if (process.env.NODE_ENV !== 'production') {
1152
1156
 
1153
1157
  var PropTypes = propTypes;
1154
1158
 
1155
- var styles$1 = {"container":"_Og09u","button":"_Jk9i-","m-0":"_1KRN6","p-0":"_gcKRj","m-1":"_yWCA-","p-1":"_vnN2l","m-2":"_oVgmY","p-2":"_OguP4","m-3":"_Kh1Mk","p-3":"_Z3Isk","m-4":"_6MAp6","p-4":"_Diglh","m-5":"_TO5Nq","p-5":"_HXLSK","m-6":"_HUNIG","p-6":"_f4arD","m-7":"_mZxzR","p-7":"_wzNuy","m-8":"_RVlle","p-8":"_OjqW3","m-9":"_Dejbg","p-9":"_islrX","m-10":"_wj-xZ","p-10":"_xz5kd","ml-0":"_B6vO4","pl-0":"_d137A","ml-1":"_F964v","pl-1":"_cUcnb","ml-2":"_sAUua","pl-2":"_ineea","ml-3":"_Q7vDo","pl-3":"_RaOUn","ml-4":"_QXOxT","pl-4":"_IOfD0","ml-5":"_yxiUW","pl-5":"_Tppy4","ml-6":"_mMW5i","pl-6":"_74GpL","ml-7":"_fFz-u","pl-7":"_QJPKy","ml-8":"_6sPXU","pl-8":"_6-6Yi","ml-9":"_9eU2j","pl-9":"_5QdLq","ml-10":"_AppHk","pl-10":"_czH97","mr-0":"_vcD-O","pr-0":"_yLhIL","mr-1":"_oSLHt","pr-1":"_whfEJ","mr-2":"_nyXH6","pr-2":"_reUdF","mr-3":"_Rs2-c","pr-3":"_sGm42","mr-4":"_vobRL","pr-4":"_wpM-u","mr-5":"_q3dAo","pr-5":"_6PIFR","mr-6":"_ZqDGE","pr-6":"_gw5Dd","mr-7":"_lFAcr","pr-7":"_b36Iz","mr-8":"_PTl3K","pr-8":"_Znc0Y","mr-9":"_P1LS0","pr-9":"_n8V-T","mr-10":"_wdhB1","pr-10":"_xiGuq","mt-0":"_wTXui","pt-0":"_qv-eO","mt-1":"_EZHmH","pt-1":"_rVDqJ","mt-2":"_Vokqr","pt-2":"_Gy6Cr","mt-3":"_W8aoH","pt-3":"_r82YV","mt-4":"_muG0F","pt-4":"_CGaJi","mt-5":"_hiY1E","pt-5":"_7v6rs","mt-6":"_bQZSd","pt-6":"_jAtjI","mt-7":"_R5w8y","pt-7":"_4mWsy","mt-8":"_Sj-di","pt-8":"_-NNao","mt-9":"_Q-fHV","pt-9":"_r8woe","mt-10":"_bSMww","pt-10":"_avmlE","mb-0":"_iCCS3","pb-0":"_gwmOn","mb-1":"_Xl7QX","pb-1":"_WUz0H","mb-2":"_XgCgc","pb-2":"_jPgTM","mb-3":"_3teTS","pb-3":"_dG1rJ","mb-4":"_b9OzE","pb-4":"_IgI2C","mb-5":"_smDd1","pb-5":"_50YOa","mb-6":"_uJfnB","pb-6":"_kl0z7","mb-7":"_L-oZk","pb-7":"_3aui0","mb-8":"_SmtYl","pb-8":"_n-QXT","mb-9":"_mkkKF","pb-9":"_jS1HG","mb-10":"_KDXkK","pb-10":"_eFwJS","mx-0":"_e-HqA","px-0":"_BSmPJ","mx-1":"_x36PW","px-1":"_Gx2xG","mx-2":"_QNnpK","px-2":"_RRwnp","mx-3":"_ZPmuA","px-3":"_f61Ux","mx-4":"_DgyA6","px-4":"_BAKix","mx-5":"_vibgJ","px-5":"_bTxPW","mx-6":"_Yj9Z7","px-6":"_fhT5q","mx-7":"_q-6lp","px-7":"_DQb93","mx-8":"_6G9nX","px-8":"_o-551","mx-9":"_2cubL","px-9":"_4JCU0","mx-10":"_KxEiD","px-10":"_czVGr","my-0":"_CqLSs","py-0":"_8uC-B","my-1":"_ZZG5X","py-1":"_aYbyO","my-2":"_w8TwE","py-2":"_qpOCn","my-3":"_PkA2e","py-3":"_OMDQd","my-4":"_aNFBd","py-4":"_eCXIU","my-5":"_apq2l","py-5":"_mk-sc","my-6":"_sh1-C","py-6":"_ZobGH","my-7":"_8758c","py-7":"_1iT1D","my-8":"_bAfQx","py-8":"_WWkd-","my-9":"_ynwaZ","py-9":"_4bOJI","my-10":"_l-I5b","py-10":"_re6Jp","m-sm-0":"_UPkcx","p-sm-0":"_t5gDA","m-sm-1":"_Rx29j","p-sm-1":"_t6SQY","m-sm-2":"_TyVqN","p-sm-2":"_Z1ogo","m-sm-3":"_gbZcT","p-sm-3":"_Mb1ST","m-sm-4":"_cUvON","p-sm-4":"_Pi4BO","m-sm-5":"_GgM3g","p-sm-5":"_uPFJ2","m-sm-6":"_cCDZS","p-sm-6":"_-e-Jr","m-sm-7":"_f2nRJ","p-sm-7":"_B6vun","m-sm-8":"_pidE0","p-sm-8":"_Qf8oe","m-sm-9":"_OyLmR","p-sm-9":"_soKag","m-sm-10":"_Hnysz","p-sm-10":"_SceBA","ml-sm-0":"_-l5XN","pl-sm-0":"_23QUK","ml-sm-1":"_3nzoa","pl-sm-1":"_Ys-wQ","ml-sm-2":"_cnl0C","pl-sm-2":"_9zniH","ml-sm-3":"_COjSH","pl-sm-3":"_ZoalV","ml-sm-4":"_7PcV0","pl-sm-4":"_yBtfl","ml-sm-5":"_0t-j9","pl-sm-5":"_lrbtT","ml-sm-6":"_441I5","pl-sm-6":"_kDiN3","ml-sm-7":"_7LdG3","pl-sm-7":"_g0gh-","ml-sm-8":"_J0xVz","pl-sm-8":"_Y6n12","ml-sm-9":"_0WKKn","pl-sm-9":"_3Seov","ml-sm-10":"_LbfWV","pl-sm-10":"_yJT8F","mr-sm-0":"_5iTiW","pr-sm-0":"_Z-yPd","mr-sm-1":"_HjxwF","pr-sm-1":"_JibpI","mr-sm-2":"_osijT","pr-sm-2":"_tlR9d","mr-sm-3":"_xxUub","pr-sm-3":"_OM4YU","mr-sm-4":"_tZTrU","pr-sm-4":"_co3SR","mr-sm-5":"_ZV8NG","pr-sm-5":"_6lrgR","mr-sm-6":"_mgH6r","pr-sm-6":"_oirFH","mr-sm-7":"_cDefz","pr-sm-7":"_PbMd1","mr-sm-8":"_GEylU","pr-sm-8":"_w9iBc","mr-sm-9":"_U-I4Y","pr-sm-9":"_VM49L","mr-sm-10":"_A-Fqb","pr-sm-10":"_jAp4X","mt-sm-0":"_kxvbF","pt-sm-0":"_-1AUk","mt-sm-1":"_utpJq","pt-sm-1":"_5aGnP","mt-sm-2":"_hH5bv","pt-sm-2":"_Lf-Hs","mt-sm-3":"_QKQTL","pt-sm-3":"_pS4ep","mt-sm-4":"_cf-lt","pt-sm-4":"_lGSoR","mt-sm-5":"_gSiyG","pt-sm-5":"_WWQxH","mt-sm-6":"_u9dIF","pt-sm-6":"_3rt-l","mt-sm-7":"_9HdeB","pt-sm-7":"_zzUxk","mt-sm-8":"_6dlAC","pt-sm-8":"_gDL-V","mt-sm-9":"_o7STq","pt-sm-9":"_7uyRq","mt-sm-10":"_VRUs5","pt-sm-10":"_nuFOu","mb-sm-0":"_gYIh5","pb-sm-0":"_9EoF6","mb-sm-1":"_h47Qi","pb-sm-1":"_zEE-R","mb-sm-2":"_qNAln","pb-sm-2":"_lAEEB","mb-sm-3":"_qz2f7","pb-sm-3":"_zDV2S","mb-sm-4":"_HziQr","pb-sm-4":"_Z8Nr-","mb-sm-5":"_2-0Mg","pb-sm-5":"_jd6YT","mb-sm-6":"_29u0R","pb-sm-6":"_rv5lz","mb-sm-7":"_34gYX","pb-sm-7":"_QK5rm","mb-sm-8":"_GTTt-","pb-sm-8":"_i9KXS","mb-sm-9":"_aOWnz","pb-sm-9":"_he9qa","mb-sm-10":"_zzLEf","pb-sm-10":"_a3Kx7","mx-sm-0":"_BxA9q","px-sm-0":"_W9ngp","mx-sm-1":"_sw7Ji","px-sm-1":"_CC5F4","mx-sm-2":"_wNsfZ","px-sm-2":"_7HUQW","mx-sm-3":"_7SvR7","px-sm-3":"_MhTrn","mx-sm-4":"_iQFZf","px-sm-4":"_-Kc-C","mx-sm-5":"_uAYfU","px-sm-5":"_zSyRo","mx-sm-6":"_M9NRe","px-sm-6":"_rqh6J","mx-sm-7":"_xC2ZW","px-sm-7":"_2ldRI","mx-sm-8":"_IdyE1","px-sm-8":"_nEOT4","mx-sm-9":"_MZcKX","px-sm-9":"_gn7RL","mx-sm-10":"_qc1L8","px-sm-10":"_eqRhA","my-sm-0":"_Fz6F6","py-sm-0":"_xO1X5","my-sm-1":"_-FpA3","py-sm-1":"_nbaB5","my-sm-2":"_O9I74","py-sm-2":"_luGVj","my-sm-3":"_HiEIn","py-sm-3":"_CYpX7","my-sm-4":"_J6Y94","py-sm-4":"_wB9Cu","my-sm-5":"_NsPY8","py-sm-5":"_mLSOY","my-sm-6":"_KsNN2","py-sm-6":"_ksiG3","my-sm-7":"_I-MIQ","py-sm-7":"_8LmM-","my-sm-8":"_N9K-q","py-sm-8":"_UmDUW","my-sm-9":"_Kx729","py-sm-9":"_T07OJ","my-sm-10":"_IW66T","py-sm-10":"_4gdB-","m-lg-0":"_zIg6p","p-lg-0":"_JuNiH","m-lg-1":"_PYsvw","p-lg-1":"_lcX2G","m-lg-2":"_FqRzp","p-lg-2":"_61LiW","m-lg-3":"_lKWuo","p-lg-3":"_c-9AA","m-lg-4":"_5iPC8","p-lg-4":"_3ucGN","m-lg-5":"_ZcKza","p-lg-5":"_53nUa","m-lg-6":"_nf5Tb","p-lg-6":"_QOkP1","m-lg-7":"_Yaf7S","p-lg-7":"_fS5OB","m-lg-8":"_3hP03","p-lg-8":"_w90dv","m-lg-9":"_eTZmn","p-lg-9":"_rEjn2","m-lg-10":"_MRZfv","p-lg-10":"_GvH8S","ml-lg-0":"_dma-K","pl-lg-0":"_dtgDg","ml-lg-1":"_lSg5Q","pl-lg-1":"_3Bq7W","ml-lg-2":"_ai140","pl-lg-2":"_eHQz2","ml-lg-3":"_IjfYo","pl-lg-3":"_mhnHv","ml-lg-4":"_gB4r4","pl-lg-4":"_GZbML","ml-lg-5":"_i2xfh","pl-lg-5":"_x9yPX","ml-lg-6":"_SeQQZ","pl-lg-6":"_wS39q","ml-lg-7":"_r8f4e","pl-lg-7":"_irihU","ml-lg-8":"_1QsQf","pl-lg-8":"_GXSU9","ml-lg-9":"_MJYz8","pl-lg-9":"_yaJGg","ml-lg-10":"_-AsD8","pl-lg-10":"_yn9Yb","mr-lg-0":"_vjC97","pr-lg-0":"_V3kGD","mr-lg-1":"_wf9z-","pr-lg-1":"_McW7I","mr-lg-2":"_kheh0","pr-lg-2":"_Q9Upz","mr-lg-3":"_zCz0A","pr-lg-3":"_YtfCI","mr-lg-4":"_qQN9B","pr-lg-4":"_S9PbV","mr-lg-5":"_bDTdZ","pr-lg-5":"_AcAC1","mr-lg-6":"_Ei18A","pr-lg-6":"_5YQVo","mr-lg-7":"_x18aw","pr-lg-7":"_N8GDD","mr-lg-8":"_OaFkM","pr-lg-8":"_-9lBB","mr-lg-9":"_52zo-","pr-lg-9":"_9T-Cb","mr-lg-10":"_IXqTb","pr-lg-10":"_zJmVt","mt-lg-0":"_2g62L","pt-lg-0":"_XBXKM","mt-lg-1":"_HMX9J","pt-lg-1":"_7rDIG","mt-lg-2":"_Y6X7U","pt-lg-2":"_fyycG","mt-lg-3":"_DvRKb","pt-lg-3":"_QKOEA","mt-lg-4":"_7qwy-","pt-lg-4":"_wl7f7","mt-lg-5":"_r-Zpt","pt-lg-5":"_-SnjV","mt-lg-6":"_q-hht","pt-lg-6":"_sOK9J","mt-lg-7":"_SUp-d","pt-lg-7":"_PugoZ","mt-lg-8":"_3NhkP","pt-lg-8":"_1n7tp","mt-lg-9":"_N7-FS","pt-lg-9":"_dnC7J","mt-lg-10":"_8IqDn","pt-lg-10":"_zMpbv","mb-lg-0":"_v5nv6","pb-lg-0":"_PMrYJ","mb-lg-1":"_O-soc","pb-lg-1":"_11FYR","mb-lg-2":"_zEeyp","pb-lg-2":"_hXqMT","mb-lg-3":"_san6w","pb-lg-3":"_7Xb0V","mb-lg-4":"_2Vzmv","pb-lg-4":"_fMirW","mb-lg-5":"_pKo-L","pb-lg-5":"_xC4Fx","mb-lg-6":"_snApN","pb-lg-6":"_b9Dsw","mb-lg-7":"_bFu0D","pb-lg-7":"_0qgZX","mb-lg-8":"_Gf3om","pb-lg-8":"_hX-O2","mb-lg-9":"_zZ-9Y","pb-lg-9":"_jk292","mb-lg-10":"_gYyhL","pb-lg-10":"_aPUfC","mx-lg-0":"_tmMx3","px-lg-0":"_GxctH","mx-lg-1":"_Ky0cs","px-lg-1":"_oGNqQ","mx-lg-2":"_9mQLc","px-lg-2":"_laRSV","mx-lg-3":"_xZFwU","px-lg-3":"_BgGbp","mx-lg-4":"_8m58X","px-lg-4":"_hosE8","mx-lg-5":"_r-0ww","px-lg-5":"_pIVfH","mx-lg-6":"_-BStC","px-lg-6":"_v42m-","mx-lg-7":"_DVgVD","px-lg-7":"_olele","mx-lg-8":"_5Vgts","px-lg-8":"_vV7Sg","mx-lg-9":"_R6Pid","px-lg-9":"_qmY7B","mx-lg-10":"_NW4OT","px-lg-10":"_i8Zad","my-lg-0":"_7PFtp","py-lg-0":"_vhTEf","my-lg-1":"_1yOov","py-lg-1":"_oKB3P","my-lg-2":"_loQJ5","py-lg-2":"_S67Pf","my-lg-3":"_HNTDI","py-lg-3":"_LWHvE","my-lg-4":"_b-KHI","py-lg-4":"_0mixG","my-lg-5":"_Vlo-t","py-lg-5":"_xLHlx","my-lg-6":"_0KXBa","py-lg-6":"_9s-me","my-lg-7":"_60cF9","py-lg-7":"_qwIHZ","my-lg-8":"_suf27","py-lg-8":"_c6pD4","my-lg-9":"_KSJpX","py-lg-9":"_C6ZV-","my-lg-10":"_JA-YG","py-lg-10":"_YuxKJ","m-md-0":"_62Zm-","p-md-0":"_7qxYP","m-md-1":"_3xHIn","p-md-1":"_A0jQv","m-md-2":"_gn3k4","p-md-2":"_EpVD0","m-md-3":"_apmcB","p-md-3":"_ldRmv","m-md-4":"_BOjUR","p-md-4":"_93an6","m-md-5":"_W5v56","p-md-5":"_SIBoU","m-md-6":"_VBmMD","p-md-6":"_7ZqTb","m-md-7":"_5Jogx","p-md-7":"_KpbGF","m-md-8":"_lw6bA","p-md-8":"_D21Xs","m-md-9":"_buMId","p-md-9":"_87RlS","m-md-10":"_ojudf","p-md-10":"_sjNOB","ml-md-0":"_V1IX-","pl-md-0":"_ZTBpt","ml-md-1":"_4jtTs","pl-md-1":"_cY-xk","ml-md-2":"_ydZsR","pl-md-2":"_MJk1L","ml-md-3":"_ocW9e","pl-md-3":"_WuBzD","ml-md-4":"_eKU4l","pl-md-4":"_cgptP","ml-md-5":"_Ov-v8","pl-md-5":"_gDnV3","ml-md-6":"_o3eWU","pl-md-6":"_Cr8hz","ml-md-7":"_sX69x","pl-md-7":"_-Ci6A","ml-md-8":"_fGNjF","pl-md-8":"_PeKiX","ml-md-9":"_yVD5i","pl-md-9":"_gxUIi","ml-md-10":"_ZPQrh","pl-md-10":"_oL88W","mr-md-0":"_rETVL","pr-md-0":"_UePrS","mr-md-1":"_wGOhL","pr-md-1":"_lXRvw","mr-md-2":"_5zLmB","pr-md-2":"_gZGtH","mr-md-3":"_jFCGk","pr-md-3":"_iimql","mr-md-4":"_yhePq","pr-md-4":"_xtBfX","mr-md-5":"_KiBHO","pr-md-5":"_WCKkT","mr-md-6":"_Q8jWF","pr-md-6":"_mu6zn","mr-md-7":"_wgy4D","pr-md-7":"_HaN0x","mr-md-8":"_0hc4i","pr-md-8":"_RomM-","mr-md-9":"_vHSBw","pr-md-9":"_4D7JM","mr-md-10":"_4kgs5","pr-md-10":"_KbOqY","mt-md-0":"_PnJEf","pt-md-0":"_Wr2Ts","mt-md-1":"_ZhVjl","pt-md-1":"_0DgRY","mt-md-2":"_WCZNy","pt-md-2":"_632Ah","mt-md-3":"_I1rX1","pt-md-3":"_yLblG","mt-md-4":"_H6sYD","pt-md-4":"_EHXef","mt-md-5":"_A-e3J","pt-md-5":"_-sV7U","mt-md-6":"_hXU9-","pt-md-6":"_n13ly","mt-md-7":"_NvbHC","pt-md-7":"_og4j4","mt-md-8":"_K3M9K","pt-md-8":"_G0D0h","mt-md-9":"_gqgsH","pt-md-9":"_2DuSs","mt-md-10":"_Bd2SX","pt-md-10":"_4zQZt","mb-md-0":"_-zK4R","pb-md-0":"_-5KU3","mb-md-1":"_DsvDi","pb-md-1":"_iBeit","mb-md-2":"_1DyrC","pb-md-2":"_We5TJ","mb-md-3":"_gHMvz","pb-md-3":"_zYpR2","mb-md-4":"_OEEgj","pb-md-4":"_Rc-ZO","mb-md-5":"_qmwpY","pb-md-5":"_t53dC","mb-md-6":"_Z7IKd","pb-md-6":"_Tr1Mj","mb-md-7":"_VAOZd","pb-md-7":"_F6Hvf","mb-md-8":"_bDJti","pb-md-8":"_-Hyix","mb-md-9":"_5NMzS","pb-md-9":"_ka3la","mb-md-10":"_m7Y4u","pb-md-10":"_GKtFW","mx-md-0":"_S-sWu","px-md-0":"_Cbp07","mx-md-1":"_0cWET","px-md-1":"_B62bC","mx-md-2":"_fk8cj","px-md-2":"_hDUD4","mx-md-3":"_3rc6m","px-md-3":"_Ybukf","mx-md-4":"_Cc05e","px-md-4":"_WuZgX","mx-md-5":"_Bizql","px-md-5":"_-p46c","mx-md-6":"_9UcKL","px-md-6":"_JBebf","mx-md-7":"_v-pvB","px-md-7":"_rA-mH","mx-md-8":"_IuwmJ","px-md-8":"_q43Ow","mx-md-9":"_d-qUi","px-md-9":"_z4nCB","mx-md-10":"_kRlX7","px-md-10":"_c-33g","my-md-0":"_PDUR4","py-md-0":"_bYhI-","my-md-1":"_GuZMi","py-md-1":"_odsUL","my-md-2":"_PnosJ","py-md-2":"_eF79-","my-md-3":"_nqJqe","py-md-3":"_Wcv28","my-md-4":"_pg-Cw","py-md-4":"_TQVBc","my-md-5":"_oq3ru","py-md-5":"_ruQ8P","my-md-6":"_udw0b","py-md-6":"_vStkc","my-md-7":"_EHkUk","py-md-7":"_oGosV","my-md-8":"_Sr4G3","py-md-8":"_eDYMt","my-md-9":"_mmQcX","py-md-9":"_J0xZx","my-md-10":"_6PNQm","py-md-10":"_N-J8O","m-xl-0":"_b9ste","p-xl-0":"_09iuo","m-xl-1":"_6sC3f","p-xl-1":"_PtZdh","m-xl-2":"_9tNY-","p-xl-2":"_ovaeX","m-xl-3":"_P2BFM","p-xl-3":"_FEEeY","m-xl-4":"_PVfE9","p-xl-4":"_65pR5","m-xl-5":"_--nhA","p-xl-5":"_jsSAE","m-xl-6":"_R6Xge","p-xl-6":"_m8aQq","m-xl-7":"_siLSo","p-xl-7":"_v7l5L","m-xl-8":"_hHbXe","p-xl-8":"_Rqlns","m-xl-9":"_oGDyI","p-xl-9":"_s-jO5","m-xl-10":"_Acff7","p-xl-10":"_r1WLU","ml-xl-0":"_R-5jP","pl-xl-0":"_4Q5-9","ml-xl-1":"_KtDt9","pl-xl-1":"_WO0X1","ml-xl-2":"_1iTCd","pl-xl-2":"_cwGpB","ml-xl-3":"_U-UBZ","pl-xl-3":"_K6-fp","ml-xl-4":"_Qj-GA","pl-xl-4":"_3HWJh","ml-xl-5":"_tHgFt","pl-xl-5":"_HDbai","ml-xl-6":"_R5iu-","pl-xl-6":"_kiBpR","ml-xl-7":"_IBpxp","pl-xl-7":"_dnEPn","ml-xl-8":"_BKEU-","pl-xl-8":"_Na3WX","ml-xl-9":"_ChhZh","pl-xl-9":"_mn3TM","ml-xl-10":"_-UMhn","pl-xl-10":"_sYOxA","mr-xl-0":"_cpZo1","pr-xl-0":"_JNcnY","mr-xl-1":"_OCoEG","pr-xl-1":"_1muOs","mr-xl-2":"_jhx4t","pr-xl-2":"_vT9VS","mr-xl-3":"_Syl0-","pr-xl-3":"_Vh6yI","mr-xl-4":"_Andea","pr-xl-4":"_IELTR","mr-xl-5":"_tR-Dd","pr-xl-5":"_tFdrE","mr-xl-6":"_MfbBj","pr-xl-6":"_-RDRT","mr-xl-7":"_2TUZ4","pr-xl-7":"_FDwKR","mr-xl-8":"_JILtJ","pr-xl-8":"_vHCTj","mr-xl-9":"_7wU9i","pr-xl-9":"_SqcZw","mr-xl-10":"_V70NV","pr-xl-10":"_-KQQG","mt-xl-0":"_sKVTL","pt-xl-0":"_ZF6Hm","mt-xl-1":"_I5EGT","pt-xl-1":"_-Ig-5","mt-xl-2":"_RIFhP","pt-xl-2":"_zaWNn","mt-xl-3":"_dPd93","pt-xl-3":"_O4wYu","mt-xl-4":"_T1XOW","pt-xl-4":"_b6dFq","mt-xl-5":"_dTI2S","pt-xl-5":"_qyuWu","mt-xl-6":"_0pvAa","pt-xl-6":"_sSQ8V","mt-xl-7":"_P-2W8","pt-xl-7":"_ek09W","mt-xl-8":"_g4vXZ","pt-xl-8":"_b2MMp","mt-xl-9":"_6JmBY","pt-xl-9":"_EG1jC","mt-xl-10":"_tHeBK","pt-xl-10":"_nYubC","mb-xl-0":"_9fyt1","pb-xl-0":"_66Js3","mb-xl-1":"_ARk1H","pb-xl-1":"_kKNTV","mb-xl-2":"_0TmE5","pb-xl-2":"_Zysst","mb-xl-3":"_XiA7F","pb-xl-3":"_SO1hI","mb-xl-4":"_W-4kw","pb-xl-4":"_-sfn8","mb-xl-5":"_NTfVD","pb-xl-5":"_LFC-6","mb-xl-6":"_pp7Gy","pb-xl-6":"_j-vtb","mb-xl-7":"_wpFKE","pb-xl-7":"_BbnyF","mb-xl-8":"_4qmjI","pb-xl-8":"_7pytN","mb-xl-9":"_B3YZo","pb-xl-9":"_cRfJG","mb-xl-10":"_NMhPX","pb-xl-10":"_Ekqdk","mx-xl-0":"_SkbmN","px-xl-0":"_JKZdb","mx-xl-1":"_UKYJi","px-xl-1":"_f-FqJ","mx-xl-2":"_gwtRl","px-xl-2":"_CSJ3f","mx-xl-3":"_tg3Yl","px-xl-3":"_EWUVo","mx-xl-4":"_p2pqT","px-xl-4":"_3DzEy","mx-xl-5":"_0xDrA","px-xl-5":"_NUhX6","mx-xl-6":"_bhY09","px-xl-6":"_mUAfo","mx-xl-7":"_Lug5G","px-xl-7":"_2kUJp","mx-xl-8":"_kTsP1","px-xl-8":"_Chv-7","mx-xl-9":"_h9kIo","px-xl-9":"_gfikM","mx-xl-10":"_3Th0M","px-xl-10":"_A4Mab","my-xl-0":"_62UqO","py-xl-0":"_BkC6O","my-xl-1":"_QJWcf","py-xl-1":"_WWFRs","my-xl-2":"_tkrQM","py-xl-2":"_-qca8","my-xl-3":"_bpoTO","py-xl-3":"_OnKLk","my-xl-4":"_o-kvn","py-xl-4":"_Icmal","my-xl-5":"_cEkTF","py-xl-5":"_mPD3K","my-xl-6":"_b2wEf","py-xl-6":"_SPrOl","my-xl-7":"_BpIhB","py-xl-7":"_9p80f","my-xl-8":"_u3RLs","py-xl-8":"_mc-ae","my-xl-9":"_Q8X-B","py-xl-9":"_SAYlD","my-xl-10":"_vUbME","py-xl-10":"_JgNyS","background-shine":"_31QK4","path":"_LID96","line":"_w2-BZ","skeleton":"_rfGkx","skeleton-animate":"_UY78C","skeleton-dark":"_KmySi","skeleton-dark-animate":"_KF46B","skeleton-transparent":"_50VFe","skeleton-transparent-animate":"_Q6BCG","semi-transparent":"_y91i5","disable":"_87Qkw","full-width-on-tablets":"_wymzG","full-width-on-mobiles":"_uhhSq","xl":"_zdQKm","lg":"_jG9wj","md":"_QrK--","sm":"_jc1W9","small-padding-on-small-mobiles":"_rS2Bk","primary":"_d-gJO","primary-bordered":"_jjfA2","primary-transparent":"_AEbcr","transparent":"_w53db","transparent-bordered":"_WW-Ps","transparent-without-shadow":"_Ltn9c","white":"_csamW","button-primary-dots-wrapper":"_Dmv-l","show":"_GkptB","button-success-icon":"_xImUU","button-text":"_ur-Oh","hide":"_-5XCZ","button-with-icon":"_ZrOKh","button-with-icon-text":"_ixQmJ","big-icon":"_8e4E7"};
1159
+ var styles$1 = {"container":"_lIpAT","button":"_sS-Yj","m-0":"_hBGrg","p-0":"_fOezx","m-1":"_R79vC","p-1":"_BGhZS","m-2":"_4WQa1","p-2":"_-hkj1","m-3":"_ePtXr","p-3":"_ihe2B","m-4":"_KplPo","p-4":"_2vDkp","m-5":"_4AqfI","p-5":"_FfAMs","m-6":"_53MvX","p-6":"_e-x4J","m-7":"_EtdrG","p-7":"_FLCe5","m-8":"_1IHYX","p-8":"_fZzmM","m-9":"_QsD9D","p-9":"_6Sr2Q","m-10":"_LvJdU","p-10":"_ah-tz","ml-0":"_De6uE","pl-0":"_aQ1ph","ml-1":"_5Bwy4","pl-1":"_j4wAR","ml-2":"_qeK50","pl-2":"_VC868","ml-3":"_LuNZb","pl-3":"_3fxbv","ml-4":"_XiU0I","pl-4":"_hPWPx","ml-5":"_xkmy7","pl-5":"_vZWUx","ml-6":"_HJ-Oe","pl-6":"_nx5bN","ml-7":"_L-cTm","pl-7":"_XyNJZ","ml-8":"_GUJTt","pl-8":"_O-OPx","ml-9":"_4DBUs","pl-9":"_W5E4J","ml-10":"_TsFNa","pl-10":"_a07G-","mr-0":"_KuY5-","pr-0":"_Zv2gF","mr-1":"_IylJL","pr-1":"_DIaMC","mr-2":"_wodzN","pr-2":"_x7vGR","mr-3":"_cg-WA","pr-3":"_-GR0e","mr-4":"_zip09","pr-4":"_mrzBz","mr-5":"_Z3SdR","pr-5":"_FOt7u","mr-6":"_DX3gj","pr-6":"_caE8K","mr-7":"_SRVDr","pr-7":"_7h7Xw","mr-8":"_bvjcP","pr-8":"_WxJl8","mr-9":"_CDXo1","pr-9":"_uftSg","mr-10":"_WqvBW","pr-10":"_75aX1","mt-0":"_lfLEb","pt-0":"_FszNW","mt-1":"_xtok6","pt-1":"_cDFtN","mt-2":"_j96uZ","pt-2":"_BX40s","mt-3":"_3--yt","pt-3":"_qkmXr","mt-4":"_DhLUo","pt-4":"_AG7V9","mt-5":"_Gn5bX","pt-5":"_5-rlk","mt-6":"_c6g6t","pt-6":"_iWQbs","mt-7":"_6X-oB","pt-7":"_i82Td","mt-8":"_uK93t","pt-8":"_ESUrY","mt-9":"_LmSrq","pt-9":"_BgZxc","mt-10":"_mPy8r","pt-10":"_ddKoS","mb-0":"_gs1hc","pb-0":"_k94Xn","mb-1":"_8XN6g","pb-1":"_lJSHs","mb-2":"_y04oG","pb-2":"_cNkcX","mb-3":"_3-Ex4","pb-3":"_UlTDL","mb-4":"_ZchCM","pb-4":"_PrDJ0","mb-5":"_Al-qI","pb-5":"_9ExxH","mb-6":"_38fJH","pb-6":"_YPJnw","mb-7":"_ViLUm","pb-7":"_YtQHK","mb-8":"_Jm2m3","pb-8":"_hQSln","mb-9":"_73cuP","pb-9":"_Hm-oe","mb-10":"_90atw","pb-10":"_GxdOW","mx-0":"_786dB","px-0":"_b-KUL","mx-1":"_1sw2D","px-1":"_pfikG","mx-2":"_ZCsfc","px-2":"_-E-rP","mx-3":"_Vzqfk","px-3":"_Evygh","mx-4":"_g6XKX","px-4":"_hzPZK","mx-5":"_6Yusw","px-5":"_43D2o","mx-6":"_l7jig","px-6":"_X4DAB","mx-7":"_xCEJ4","px-7":"_kFsKL","mx-8":"_bcZ3x","px-8":"_qKJ-o","mx-9":"_pmzk-","px-9":"_5kFZh","mx-10":"_ZtyHL","px-10":"_RzSP4","my-0":"_iGkHt","py-0":"_tFXK8","my-1":"_9p151","py-1":"_1ExYH","my-2":"_hDX-y","py-2":"_j2Iqz","my-3":"_ZoP-i","py-3":"_JiyfX","my-4":"_6dHeQ","py-4":"_Val1l","my-5":"_yF8w9","py-5":"_3Do00","my-6":"_5ATW7","py-6":"_EqQi0","my-7":"_6Kng-","py-7":"_kFB05","my-8":"_fqkrf","py-8":"_wkYlc","my-9":"_yC6ha","py-9":"_nR4hK","my-10":"_46v2E","py-10":"_yjbuZ","m-sm-0":"_mXg7O","p-sm-0":"_sRkzF","m-sm-1":"_uh76t","p-sm-1":"_mnvOq","m-sm-2":"_-Lxwk","p-sm-2":"_9AoV6","m-sm-3":"_k6uGI","p-sm-3":"_FPlck","m-sm-4":"_XWNGm","p-sm-4":"_UhY4z","m-sm-5":"_nqmEm","p-sm-5":"_O3yzT","m-sm-6":"_1C7QT","p-sm-6":"_yR3CC","m-sm-7":"_vlqMl","p-sm-7":"_otIfI","m-sm-8":"_f-GUL","p-sm-8":"_oMnLQ","m-sm-9":"_Klhy3","p-sm-9":"_xYdqe","m-sm-10":"_jg7tY","p-sm-10":"_-28KU","ml-sm-0":"_6hhVb","pl-sm-0":"_WV4uZ","ml-sm-1":"_u--dD","pl-sm-1":"_k2dSZ","ml-sm-2":"_ng1Wx","pl-sm-2":"_A6pLt","ml-sm-3":"_OKwcI","pl-sm-3":"_uxcE6","ml-sm-4":"_dHy5x","pl-sm-4":"_loKKN","ml-sm-5":"_pWXnn","pl-sm-5":"_6KcZ0","ml-sm-6":"_8DdT4","pl-sm-6":"_atdfH","ml-sm-7":"_-BksR","pl-sm-7":"_B6uGl","ml-sm-8":"_rL6Yi","pl-sm-8":"_L0Gt6","ml-sm-9":"_sDCuc","pl-sm-9":"_5ndTT","ml-sm-10":"_d0sOv","pl-sm-10":"_MzCci","mr-sm-0":"_TxpxL","pr-sm-0":"_ReTjB","mr-sm-1":"_ZDd-C","pr-sm-1":"_6ux6P","mr-sm-2":"_SbIys","pr-sm-2":"_0dAjY","mr-sm-3":"_WT-FE","pr-sm-3":"_hgzpB","mr-sm-4":"_ovLOk","pr-sm-4":"_YVXRD","mr-sm-5":"_3gKfj","pr-sm-5":"_GKqKE","mr-sm-6":"_EJ3Ig","pr-sm-6":"_pKU7W","mr-sm-7":"_MfWyc","pr-sm-7":"_439vk","mr-sm-8":"_HsLqa","pr-sm-8":"_Afu8-","mr-sm-9":"_k-uXQ","pr-sm-9":"_GSZg6","mr-sm-10":"_buR-E","pr-sm-10":"_GoGHq","mt-sm-0":"_3eC5V","pt-sm-0":"_w0Row","mt-sm-1":"_lFsar","pt-sm-1":"_rhMZX","mt-sm-2":"_HchNc","pt-sm-2":"_Xyn5a","mt-sm-3":"_INU0e","pt-sm-3":"_i9zkC","mt-sm-4":"_d1xqQ","pt-sm-4":"_eMU-M","mt-sm-5":"_gYMLN","pt-sm-5":"_sG2g-","mt-sm-6":"_U4BDm","pt-sm-6":"_nagya","mt-sm-7":"_f4nLP","pt-sm-7":"_3jMHw","mt-sm-8":"_hZW3J","pt-sm-8":"_woC7I","mt-sm-9":"_SFf2s","pt-sm-9":"_nuLoR","mt-sm-10":"_k1lF9","pt-sm-10":"_WG3-N","mb-sm-0":"_fQPR-","pb-sm-0":"_eL6LV","mb-sm-1":"_Z7gTR","pb-sm-1":"_OdGhD","mb-sm-2":"_dkjwo","pb-sm-2":"_kKhvE","mb-sm-3":"_meX0E","pb-sm-3":"_kh7Ku","mb-sm-4":"_rrb92","pb-sm-4":"_aytJc","mb-sm-5":"_wPkH4","pb-sm-5":"_1nZ-9","mb-sm-6":"_MkdDA","pb-sm-6":"_BxNLc","mb-sm-7":"_Nfm1A","pb-sm-7":"_-r452","mb-sm-8":"_K1omF","pb-sm-8":"_4-6gt","mb-sm-9":"_OUWsR","pb-sm-9":"_7DXr5","mb-sm-10":"_wZv7f","pb-sm-10":"_21WIP","mx-sm-0":"_hCRDg","px-sm-0":"_Bdj31","mx-sm-1":"_sx6bH","px-sm-1":"_jQXbZ","mx-sm-2":"_aCjIb","px-sm-2":"_-DBsZ","mx-sm-3":"_p2bFN","px-sm-3":"_d6ice","mx-sm-4":"_GZmNE","px-sm-4":"_7D10W","mx-sm-5":"_tKkEN","px-sm-5":"_J2iH5","mx-sm-6":"_iJju-","px-sm-6":"_m2ygK","mx-sm-7":"_chPCu","px-sm-7":"_C0aVt","mx-sm-8":"_twRB-","px-sm-8":"_6DezI","mx-sm-9":"_z1iZL","px-sm-9":"_HLE-F","mx-sm-10":"_F58U0","px-sm-10":"_Mat2S","my-sm-0":"_nADuT","py-sm-0":"_yu79u","my-sm-1":"_TEHyf","py-sm-1":"_MkRV5","my-sm-2":"_wfxJN","py-sm-2":"_qjIa5","my-sm-3":"_ch7TX","py-sm-3":"_0ZM5Q","my-sm-4":"_KQyj3","py-sm-4":"_npV56","my-sm-5":"_antvz","py-sm-5":"_qK29t","my-sm-6":"_PIZw6","py-sm-6":"_kwzra","my-sm-7":"_IPjVc","py-sm-7":"_NPJ-2","my-sm-8":"_Sxu2p","py-sm-8":"_VUG-4","my-sm-9":"_mLy-T","py-sm-9":"_U-1Tz","my-sm-10":"_6LGF-","py-sm-10":"_1I7Qo","m-lg-0":"_7JHxT","p-lg-0":"_dZxSG","m-lg-1":"_ap69K","p-lg-1":"_yAiEU","m-lg-2":"_cu0Gq","p-lg-2":"_p2Nvp","m-lg-3":"_ipTnO","p-lg-3":"_uekmi","m-lg-4":"_Ocj1U","p-lg-4":"_T5xZ0","m-lg-5":"_9QwAr","p-lg-5":"_S73RR","m-lg-6":"_TQDUS","p-lg-6":"_SVpzt","m-lg-7":"_u7-7x","p-lg-7":"_tVwwR","m-lg-8":"_VMheR","p-lg-8":"_dnoel","m-lg-9":"_bs68b","p-lg-9":"_-fPka","m-lg-10":"_JaRq8","p-lg-10":"_222SK","ml-lg-0":"_snW5C","pl-lg-0":"_cbC4p","ml-lg-1":"_ZcZqo","pl-lg-1":"_Ox1R-","ml-lg-2":"_GYhhL","pl-lg-2":"_RQnGa","ml-lg-3":"_PUix3","pl-lg-3":"_TXjNe","ml-lg-4":"_ctO4e","pl-lg-4":"_HGdnK","ml-lg-5":"_0kAql","pl-lg-5":"_j374-","ml-lg-6":"_DTSzU","pl-lg-6":"_f8fRt","ml-lg-7":"_SOGpN","pl-lg-7":"_ftCov","ml-lg-8":"_yyg3O","pl-lg-8":"_es-pp","ml-lg-9":"_ujiYm","pl-lg-9":"_hEH2f","ml-lg-10":"_sOymp","pl-lg-10":"_zABMD","mr-lg-0":"_bZvOK","pr-lg-0":"_1MjdX","mr-lg-1":"_lVGe-","pr-lg-1":"_hJzV5","mr-lg-2":"_9az71","pr-lg-2":"_vBVKt","mr-lg-3":"_SK-xp","pr-lg-3":"_BymTx","mr-lg-4":"_C-P-K","pr-lg-4":"_oDktY","mr-lg-5":"_e8X2c","pr-lg-5":"_XugCG","mr-lg-6":"_CycFS","pr-lg-6":"_aXn7x","mr-lg-7":"_woi9n","pr-lg-7":"_Xz9XT","mr-lg-8":"_p4H3g","pr-lg-8":"_2GHoq","mr-lg-9":"_OZukC","pr-lg-9":"_ckY7k","mr-lg-10":"_tu3W5","pr-lg-10":"_9v3FG","mt-lg-0":"_I-1g6","pt-lg-0":"_cUyFD","mt-lg-1":"_c94QP","pt-lg-1":"_g75ry","mt-lg-2":"_XiT9Y","pt-lg-2":"_OzwIr","mt-lg-3":"_TZnYh","pt-lg-3":"_qC-3V","mt-lg-4":"_ClD8h","pt-lg-4":"_n1T93","mt-lg-5":"_yfqL8","pt-lg-5":"_oRkf6","mt-lg-6":"_6sndc","pt-lg-6":"_zKuFI","mt-lg-7":"_61kz3","pt-lg-7":"_5Q2hr","mt-lg-8":"_s2ReT","pt-lg-8":"_Ap8SS","mt-lg-9":"_bV6Hp","pt-lg-9":"_G5Dl9","mt-lg-10":"_hSJ91","pt-lg-10":"_amgjj","mb-lg-0":"_p-7me","pb-lg-0":"_ys8Fm","mb-lg-1":"_ZFPzR","pb-lg-1":"_Low3Q","mb-lg-2":"_UKfD5","pb-lg-2":"_Z4xYz","mb-lg-3":"_WYCZq","pb-lg-3":"_lOmpq","mb-lg-4":"_3f13Q","pb-lg-4":"_tfvEW","mb-lg-5":"_DxAtv","pb-lg-5":"_lN1KV","mb-lg-6":"_pEAAo","pb-lg-6":"_9pLfP","mb-lg-7":"_lZzWZ","pb-lg-7":"_E76Lg","mb-lg-8":"_Biywb","pb-lg-8":"_PKNGt","mb-lg-9":"_af7LP","pb-lg-9":"_769vF","mb-lg-10":"_p6W2n","pb-lg-10":"_44r6t","mx-lg-0":"_noonL","px-lg-0":"_g6n-m","mx-lg-1":"_V3fJC","px-lg-1":"_h-048","mx-lg-2":"_VBXFM","px-lg-2":"_yXjeI","mx-lg-3":"_anxPB","px-lg-3":"_umXxh","mx-lg-4":"_arYWt","px-lg-4":"_v21qY","mx-lg-5":"_VJrBv","px-lg-5":"_Wg7-s","mx-lg-6":"_qiDC7","px-lg-6":"_1VXpg","mx-lg-7":"_d0c15","px-lg-7":"_sfSeF","mx-lg-8":"_2gYLA","px-lg-8":"_DEL7d","mx-lg-9":"_KmU1j","px-lg-9":"_Qs2ud","mx-lg-10":"_cEBsK","px-lg-10":"_mQH7b","my-lg-0":"_ag2WO","py-lg-0":"_lnVBo","my-lg-1":"_xEHQX","py-lg-1":"_9Tj2M","my-lg-2":"_Iqbzp","py-lg-2":"_8tcVx","my-lg-3":"_caNHW","py-lg-3":"_XJ-2h","my-lg-4":"_6q91a","py-lg-4":"_EwkV-","my-lg-5":"_vAyw8","py-lg-5":"_5fbq2","my-lg-6":"_15LIk","py-lg-6":"_HIyvD","my-lg-7":"_kBk-L","py-lg-7":"_t5Eqq","my-lg-8":"_7QdOv","py-lg-8":"_mWXQT","my-lg-9":"_AgF1j","py-lg-9":"_Hw03a","my-lg-10":"_lgtEt","py-lg-10":"_VLUO-","m-md-0":"_bZzK1","p-md-0":"_hf1u1","m-md-1":"_D90hf","p-md-1":"_T8Wci","m-md-2":"_OV2C9","p-md-2":"_GFg-F","m-md-3":"_tOGww","p-md-3":"_p0NdJ","m-md-4":"_gUtm-","p-md-4":"_92JAP","m-md-5":"_V4DwP","p-md-5":"_KzYIR","m-md-6":"_RYzMI","p-md-6":"_bV-UI","m-md-7":"_bZ8rT","p-md-7":"_sz5lw","m-md-8":"_Tt85A","p-md-8":"_o9XsL","m-md-9":"_5Z2zG","p-md-9":"_QFUvw","m-md-10":"_o-CSv","p-md-10":"_I0UW7","ml-md-0":"_Ec-jt","pl-md-0":"_AsNUW","ml-md-1":"_FkvyK","pl-md-1":"_eWpHd","ml-md-2":"_C-N9j","pl-md-2":"_f4IXC","ml-md-3":"_i4rpE","pl-md-3":"_u1wxV","ml-md-4":"_bfpFB","pl-md-4":"_LFkDV","ml-md-5":"_ChenT","pl-md-5":"_Tseed","ml-md-6":"_5OVzE","pl-md-6":"_kKZuw","ml-md-7":"_HkEvd","pl-md-7":"_-UCQ1","ml-md-8":"_Mil4J","pl-md-8":"_ibj8N","ml-md-9":"_hZgvD","pl-md-9":"_x58o7","ml-md-10":"_aNTRb","pl-md-10":"_B9Ytk","mr-md-0":"_5fzNR","pr-md-0":"_UcmnK","mr-md-1":"_7GSVQ","pr-md-1":"_lKZ6y","mr-md-2":"_Vuc2l","pr-md-2":"_OWoeF","mr-md-3":"_GfGNW","pr-md-3":"_039xq","mr-md-4":"_XUUw7","pr-md-4":"_hNdK8","mr-md-5":"_PchvO","pr-md-5":"_YBTBv","mr-md-6":"_irZPz","pr-md-6":"_xez9v","mr-md-7":"_IWCJD","pr-md-7":"_Nymwz","mr-md-8":"_1ypEg","pr-md-8":"_hJvwk","mr-md-9":"_AisV-","pr-md-9":"_6jqua","mr-md-10":"_LdBUv","pr-md-10":"_Rhahl","mt-md-0":"_iI75A","pt-md-0":"_GCK2h","mt-md-1":"_QoRcE","pt-md-1":"_Q3gZh","mt-md-2":"_rzNrf","pt-md-2":"_mrtOR","mt-md-3":"_-Xx-x","pt-md-3":"_vhZY4","mt-md-4":"_Ie5M9","pt-md-4":"_Bv-Vz","mt-md-5":"_sC4OE","pt-md-5":"_sZzfz","mt-md-6":"_b8qW3","pt-md-6":"_sca5l","mt-md-7":"_Pn6m9","pt-md-7":"_9klOR","mt-md-8":"_oY4i-","pt-md-8":"_QpcKU","mt-md-9":"_-PssV","pt-md-9":"_IBITO","mt-md-10":"_hmDGa","pt-md-10":"_rPOnf","mb-md-0":"_KsSuI","pb-md-0":"_E01ZW","mb-md-1":"_mu8n4","pb-md-1":"_obt8N","mb-md-2":"_4uUmS","pb-md-2":"_eCQut","mb-md-3":"_gckFx","pb-md-3":"_v76WA","mb-md-4":"_HNG1G","pb-md-4":"_WF2cS","mb-md-5":"_y0d7f","pb-md-5":"_Ulg5o","mb-md-6":"_gGNca","pb-md-6":"_L6tTJ","mb-md-7":"_JFKoe","pb-md-7":"_cotbI","mb-md-8":"_zWuLC","pb-md-8":"_PZ98d","mb-md-9":"_0OLPw","pb-md-9":"_diSZ0","mb-md-10":"_tZv9r","pb-md-10":"_8DINx","mx-md-0":"_TlILw","px-md-0":"_nYb1A","mx-md-1":"_8F9Eu","px-md-1":"_zdtgY","mx-md-2":"_Hf2VU","px-md-2":"_R7ntT","mx-md-3":"_7koGZ","px-md-3":"_SjYZ0","mx-md-4":"_mfX1U","px-md-4":"_wpmO4","mx-md-5":"_yWbVN","px-md-5":"_c-PDJ","mx-md-6":"_F98A-","px-md-6":"_k2aB-","mx-md-7":"_PyjZi","px-md-7":"_1p7LO","mx-md-8":"_at5B-","px-md-8":"_Wlop7","mx-md-9":"_MP-IT","px-md-9":"_ZEJLn","mx-md-10":"_t-qxH","px-md-10":"_m2jcH","my-md-0":"_mamXD","py-md-0":"_XfnLL","my-md-1":"_wltQA","py-md-1":"_kMSov","my-md-2":"_PB9Lu","py-md-2":"_ZHQxJ","my-md-3":"_ROfrO","py-md-3":"_5pjW-","my-md-4":"_asOWk","py-md-4":"_521lJ","my-md-5":"_sfKXT","py-md-5":"_0hhLg","my-md-6":"_vBIkT","py-md-6":"_mh-mU","my-md-7":"_SbaIW","py-md-7":"_4U--m","my-md-8":"_8Ml4g","py-md-8":"_8CAbC","my-md-9":"_2W5Vi","py-md-9":"_ifVgs","my-md-10":"_jOwwL","py-md-10":"_xGEHg","m-xl-0":"_Cmi8h","p-xl-0":"_YOJnv","m-xl-1":"_IlYRc","p-xl-1":"_qg39r","m-xl-2":"_NZu1F","p-xl-2":"_ChCeZ","m-xl-3":"_wCJFO","p-xl-3":"_s5DXB","m-xl-4":"_-ooyS","p-xl-4":"_1rcFF","m-xl-5":"_2--cB","p-xl-5":"_0s8cD","m-xl-6":"_zMbs-","p-xl-6":"_qAR79","m-xl-7":"_sRWyz","p-xl-7":"_ykFCJ","m-xl-8":"_dj226","p-xl-8":"_XLB7-","m-xl-9":"_eM-R4","p-xl-9":"_QuQVl","m-xl-10":"_UUuwy","p-xl-10":"_nDqX9","ml-xl-0":"_LL8WU","pl-xl-0":"_AIPph","ml-xl-1":"_pKFo-","pl-xl-1":"_tQEXN","ml-xl-2":"_F-wn7","pl-xl-2":"_wcxv3","ml-xl-3":"_M94zg","pl-xl-3":"_I3KoK","ml-xl-4":"_0PzeG","pl-xl-4":"_lzci3","ml-xl-5":"_XRI4C","pl-xl-5":"_XlhyA","ml-xl-6":"_GjzL0","pl-xl-6":"_ASrOm","ml-xl-7":"_-0WjA","pl-xl-7":"_hx5P8","ml-xl-8":"_XlbUH","pl-xl-8":"_Vonli","ml-xl-9":"_LwuSL","pl-xl-9":"_MxuFJ","ml-xl-10":"_v7xZI","pl-xl-10":"_Tvo-Z","mr-xl-0":"_SzVWx","pr-xl-0":"_K1dhq","mr-xl-1":"_JOZtq","pr-xl-1":"_c1i37","mr-xl-2":"_R3B8Q","pr-xl-2":"_63cME","mr-xl-3":"_91LCJ","pr-xl-3":"_WxNaS","mr-xl-4":"_BauAg","pr-xl-4":"_V6rST","mr-xl-5":"_H0Uy4","pr-xl-5":"_idyBA","mr-xl-6":"_lIBS-","pr-xl-6":"_hm7f2","mr-xl-7":"_DcV1a","pr-xl-7":"_L9DAM","mr-xl-8":"_M62Cx","pr-xl-8":"_nso5O","mr-xl-9":"_M-vkg","pr-xl-9":"_Jm-de","mr-xl-10":"_V5v9Y","pr-xl-10":"_jt-a5","mt-xl-0":"_YPHmA","pt-xl-0":"_XVXEh","mt-xl-1":"_pJbYc","pt-xl-1":"_i-ZXc","mt-xl-2":"_SHsME","pt-xl-2":"_ak-Hh","mt-xl-3":"_wzbs7","pt-xl-3":"_py3lR","mt-xl-4":"_HBXKA","pt-xl-4":"_GQBlv","mt-xl-5":"_5d6Ee","pt-xl-5":"_KFPkO","mt-xl-6":"_Yf-yF","pt-xl-6":"_1e6oC","mt-xl-7":"_kg9lU","pt-xl-7":"_SHs7f","mt-xl-8":"_KXugL","pt-xl-8":"_VyRfA","mt-xl-9":"_EOyB7","pt-xl-9":"_5KMcS","mt-xl-10":"_8W-Zj","pt-xl-10":"_cz8iz","mb-xl-0":"_rWALs","pb-xl-0":"_LpkfT","mb-xl-1":"_RzmHQ","pb-xl-1":"_6ad54","mb-xl-2":"_Ajc4e","pb-xl-2":"_SbX8t","mb-xl-3":"_vSzzB","pb-xl-3":"_yidEJ","mb-xl-4":"_mrCP3","pb-xl-4":"_3TrW-","mb-xl-5":"_6j8-6","pb-xl-5":"_D1WrN","mb-xl-6":"_XDRU9","pb-xl-6":"_dcA8T","mb-xl-7":"_-i7kC","pb-xl-7":"_81QE4","mb-xl-8":"_X9-zp","pb-xl-8":"_HTClM","mb-xl-9":"_klb-D","pb-xl-9":"_RReN9","mb-xl-10":"_vPsb7","pb-xl-10":"_OVfeI","mx-xl-0":"_YNCB1","px-xl-0":"_hiVA4","mx-xl-1":"_k6kz-","px-xl-1":"_rONSC","mx-xl-2":"_pBneY","px-xl-2":"_po-3F","mx-xl-3":"_Bpbr7","px-xl-3":"_KdGyy","mx-xl-4":"_brh6E","px-xl-4":"_qqxT0","mx-xl-5":"_BfzzU","px-xl-5":"_R-Rw5","mx-xl-6":"_sSR5n","px-xl-6":"_thByS","mx-xl-7":"_r5nPW","px-xl-7":"_Qn6um","mx-xl-8":"_J9EDO","px-xl-8":"_9rkVI","mx-xl-9":"_Mltks","px-xl-9":"_g-Ham","mx-xl-10":"_sbya6","px-xl-10":"_8-jLj","my-xl-0":"_5yWBG","py-xl-0":"_xbHHG","my-xl-1":"_PlYBL","py-xl-1":"_F3Fon","my-xl-2":"_tsmUe","py-xl-2":"_a-0sQ","my-xl-3":"_sY3wJ","py-xl-3":"_iMcG-","my-xl-4":"_oHAzn","py-xl-4":"_SVfuw","my-xl-5":"_PvaIf","py-xl-5":"_J1xNt","my-xl-6":"_opQCd","py-xl-6":"_BykWn","my-xl-7":"_wYtgV","py-xl-7":"_rWN6g","my-xl-8":"_QHTpr","py-xl-8":"_6lwHD","my-xl-9":"_sKUSa","py-xl-9":"_HEg44","my-xl-10":"_mR1Ig","py-xl-10":"_-KK9e","background-shine":"_GS93D","path":"_Yio2J","line":"_hUBrW","skeleton":"_jhzCK","skeleton-animate":"_E3Vdv","skeleton-dark":"_wQ36Y","skeleton-dark-animate":"_j-rmG","skeleton-transparent":"_trTiX","skeleton-transparent-animate":"_4QQUW","semi-transparent":"_jW9cZ","disable":"_07-2N","full-width-on-tablets":"_at3Is","full-width-on-mobiles":"_7mVhH","xl":"_YBEjy","lg":"_4T1JY","md":"_y81Q7","sm":"_HlFvs","small-padding-on-small-mobiles":"_pC5i6","primary":"_rf33o","primary-bordered":"_bpdoC","primary-transparent":"_FNwOe","transparent":"_9LspZ","transparent-bordered":"_HgM7r","transparent-without-shadow":"_tkp-m","white":"_bv597","white-flat":"_IhewT","button-primary-dots-wrapper":"_OEKG8","show":"_MQYPo","button-success-icon":"_Y24W2","button-text":"_o-rLq","hide":"_4GC9-","button-with-icon":"_m1W6m","button-with-icon-text":"_75-fw","big-icon":"_gHcQi"};
1156
1160
 
1157
- var styles = {"container":"_wfTsj","m-0":"_UeiuB","p-0":"_QD4AZ","m-1":"_wOM1E","p-1":"_kJ3GD","m-2":"_5G5Rf","p-2":"_dyuup","m-3":"_m4kZr","p-3":"_-aSKV","m-4":"_lqeth","p-4":"_WFhaj","m-5":"_bgee8","p-5":"_Y2Iup","m-6":"_c873k","p-6":"_Huak-","m-7":"_c2rt4","p-7":"_2dT3Y","m-8":"_7rQUz","p-8":"_fjzT8","m-9":"_jmGJQ","p-9":"_CTpOZ","m-10":"_lEJ9M","p-10":"_1LfZ2","ml-0":"_j6sNe","pl-0":"_i8R7s","ml-1":"_oM6Eu","pl-1":"_QllX8","ml-2":"_r3xcV","pl-2":"_fd0jL","ml-3":"_SP5MI","pl-3":"_wQD-b","ml-4":"_uV9BF","pl-4":"_k1Kla","ml-5":"_FTlGy","pl-5":"_k20cZ","ml-6":"_5gR0D","pl-6":"_ICAcq","ml-7":"_-PQGU","pl-7":"_VxSDF","ml-8":"_bKyKZ","pl-8":"_2DqEG","ml-9":"_1SlOv","pl-9":"_EIiNs","ml-10":"_5WCGB","pl-10":"_qdKd3","mr-0":"_JWuXP","pr-0":"_5aqFq","mr-1":"_GTimu","pr-1":"_VC6Mm","mr-2":"_iuK1E","pr-2":"_YREDe","mr-3":"_qttq2","pr-3":"_FRB7c","mr-4":"_tyLXy","pr-4":"_khAbL","mr-5":"_-pPmp","pr-5":"_Zn6P3","mr-6":"_UXDvD","pr-6":"_Pyjz-","mr-7":"_ydv6O","pr-7":"_W2-PF","mr-8":"_AeBpV","pr-8":"_GNhM6","mr-9":"_6r58X","pr-9":"_nDQS4","mr-10":"_z6oMu","pr-10":"_NqF8M","mt-0":"_5BywF","pt-0":"_G3lb7","mt-1":"_O8qGt","pt-1":"_KxUDK","mt-2":"_feZvx","pt-2":"_i4LGd","mt-3":"_8rWTr","pt-3":"_5KtzE","mt-4":"_22EES","pt-4":"_ktDxC","mt-5":"_hNJ8a","pt-5":"_l-BdA","mt-6":"_V7rTE","pt-6":"_yO380","mt-7":"_64Gbc","pt-7":"_slV9V","mt-8":"_PAPZ0","pt-8":"_SlH81","mt-9":"_OmKU7","pt-9":"_m4Y5T","mt-10":"_N7MOD","pt-10":"_5EmMY","mb-0":"_umP3K","pb-0":"_tdjdM","mb-1":"_RUpVI","pb-1":"_qhSG-","mb-2":"_UE6hY","pb-2":"_bhwY3","mb-3":"_gCNY5","pb-3":"_CT9SA","mb-4":"_hXf14","pb-4":"_dBd4j","mb-5":"_BJm2f","pb-5":"_osAXf","mb-6":"_sksVG","pb-6":"_vq2P1","mb-7":"_GGqWv","pb-7":"_Wp-xn","mb-8":"_ao8-b","pb-8":"_Fcz6J","mb-9":"_HTDCN","pb-9":"_j2geM","mb-10":"_tQ3f4","pb-10":"_k5-cY","mx-0":"_C-RwH","px-0":"_fGmBQ","mx-1":"_SJIAI","px-1":"_V6h6n","mx-2":"_RpAL-","px-2":"_MtnJr","mx-3":"_bJAjq","loading-dots":"_i9YR0","big":"_Gf-5X","dot":"_yU4CC","px-3":"_bKF6h","mx-4":"_2YwpF","px-4":"_sv9HO","mx-5":"_fyywB","px-5":"_PAvUg","mx-6":"_-7Y93","px-6":"_2HnrR","mx-7":"_mO0GJ","px-7":"_-XBUb","mx-8":"_rPzNl","px-8":"_lxUkB","mx-9":"_wtwwN","px-9":"_ewGa-","mx-10":"_CUJzg","px-10":"_9fyow","my-0":"_D3hCP","py-0":"_fUhkb","my-1":"_-gS0u","py-1":"_DCjg-","my-2":"_REwX3","py-2":"_5qEqQ","my-3":"_4P9yd","py-3":"_3Q6jo","my-4":"_pJ9JL","py-4":"_fvyEP","my-5":"_7HH0Y","py-5":"_pfPnT","my-6":"_HMzw4","py-6":"_nGGuj","my-7":"_ZQcHb","py-7":"_Q5rCt","my-8":"_yurdg","py-8":"_z2Rnm","my-9":"_SGsqH","py-9":"_RkTBo","my-10":"_hgG--","py-10":"_iKSyb","m-sm-0":"_hG8Pd","p-sm-0":"_paicL","m-sm-1":"_zYVem","p-sm-1":"_Iifls","m-sm-2":"_C0HAk","p-sm-2":"_tyMH8","m-sm-3":"_Nw8NT","p-sm-3":"_mOvjR","m-sm-4":"_auqaY","p-sm-4":"_nqq-T","m-sm-5":"_uC7a4","p-sm-5":"_QmBt-","m-sm-6":"_E1Mby","p-sm-6":"_2b-XB","m-sm-7":"_shE-L","p-sm-7":"_DZiE4","m-sm-8":"_VrAWC","p-sm-8":"_wBvI1","m-sm-9":"_nT5hR","p-sm-9":"_utagJ","m-sm-10":"_suXWh","p-sm-10":"_HqYvz","ml-sm-0":"_XKTYr","pl-sm-0":"_-69hr","ml-sm-1":"_EnQBB","pl-sm-1":"_OBDbZ","ml-sm-2":"_4uEtT","pl-sm-2":"_jxnnV","ml-sm-3":"_4dyy7","pl-sm-3":"_fcp9m","ml-sm-4":"_Su7vR","pl-sm-4":"_iGsH0","ml-sm-5":"_j5bIe","pl-sm-5":"_iiiem","ml-sm-6":"_OSCRC","pl-sm-6":"_a6Ij8","ml-sm-7":"_cESaw","pl-sm-7":"_PZAKp","ml-sm-8":"_u1e7W","pl-sm-8":"_MMjU3","ml-sm-9":"_AEo-h","pl-sm-9":"_g6Qm-","ml-sm-10":"_RSzPa","pl-sm-10":"_5lIjk","mr-sm-0":"_iq-8E","pr-sm-0":"_6e7Oo","mr-sm-1":"_eRKuI","pr-sm-1":"_HaKr0","mr-sm-2":"_sl8Y1","pr-sm-2":"_-eAaQ","mr-sm-3":"_hqMXk","pr-sm-3":"_-nPxR","mr-sm-4":"_PFLZC","pr-sm-4":"_bz8kn","mr-sm-5":"_IDOFd","pr-sm-5":"_YphYe","mr-sm-6":"_DFP8e","pr-sm-6":"_uffDW","mr-sm-7":"_K4gIP","pr-sm-7":"_mFIwC","mr-sm-8":"_ZnbXS","pr-sm-8":"_SJ5sd","mr-sm-9":"_I4pB1","pr-sm-9":"_7Be-A","mr-sm-10":"_BlQpX","pr-sm-10":"_zoDIK","mt-sm-0":"_PpfXn","pt-sm-0":"_MLL-T","mt-sm-1":"_sFLGW","pt-sm-1":"_cssHG","mt-sm-2":"_-CEBu","pt-sm-2":"_3164x","mt-sm-3":"_Q-yYF","pt-sm-3":"_aSP--","mt-sm-4":"_HCnTw","pt-sm-4":"_pkP3Z","mt-sm-5":"_wpfr4","pt-sm-5":"_090aI","mt-sm-6":"_1YJBr","pt-sm-6":"_jYnK3","mt-sm-7":"_1f6jW","pt-sm-7":"_yPAeS","mt-sm-8":"_dNsVh","pt-sm-8":"_5n5Di","mt-sm-9":"_4RACJ","pt-sm-9":"_lgByZ","mt-sm-10":"_SBIrM","pt-sm-10":"_YsBHF","mb-sm-0":"_-z2mG","pb-sm-0":"_uz-nV","mb-sm-1":"_bPTQE","pb-sm-1":"_qTKZa","mb-sm-2":"_DWs80","pb-sm-2":"_7Pkyh","mb-sm-3":"_c5AbJ","pb-sm-3":"_0BQOV","mb-sm-4":"_V1gvx","pb-sm-4":"_s56MP","mb-sm-5":"_abqTk","pb-sm-5":"_YVQSJ","mb-sm-6":"_URgQP","pb-sm-6":"_3cTRb","mb-sm-7":"_tbZgH","pb-sm-7":"_oprz5","mb-sm-8":"_1tsmq","pb-sm-8":"_rp6hG","mb-sm-9":"_HI-9l","pb-sm-9":"_FnTxa","mb-sm-10":"_RHo4c","pb-sm-10":"_PZUR0","mx-sm-0":"_AvLmU","px-sm-0":"_PtUTn","mx-sm-1":"_WdN3k","px-sm-1":"_ytExi","mx-sm-2":"_RWE1V","px-sm-2":"_vw43o","mx-sm-3":"_Cbm5H","px-sm-3":"_P-Cf6","mx-sm-4":"_pjfwR","px-sm-4":"_WtStS","mx-sm-5":"_9a-hP","px-sm-5":"_JMDVm","mx-sm-6":"_OS2my","px-sm-6":"_-GrIc","mx-sm-7":"_BCsIq","px-sm-7":"_WhZnF","mx-sm-8":"_1aj2C","px-sm-8":"_THUvZ","mx-sm-9":"_JGLYJ","px-sm-9":"_A-5uV","mx-sm-10":"_va7ij","px-sm-10":"_XIozX","my-sm-0":"_iYNXh","py-sm-0":"_A4kOE","my-sm-1":"_vMEVL","py-sm-1":"_Xp5yf","my-sm-2":"_VXJt9","py-sm-2":"_LFrIT","my-sm-3":"_KkriU","py-sm-3":"_5locy","my-sm-4":"_FbhGv","py-sm-4":"_lhkY0","my-sm-5":"_iI3NO","py-sm-5":"_YPAWx","my-sm-6":"_nsvtx","py-sm-6":"_fzqyr","my-sm-7":"_HCcpN","py-sm-7":"_yw1CE","my-sm-8":"_FvOZ-","py-sm-8":"_H3dR0","my-sm-9":"_AgJBK","py-sm-9":"_1xEHl","my-sm-10":"_TkKl8","py-sm-10":"_B3-Sv","m-lg-0":"_67BGW","p-lg-0":"_hLq7o","m-lg-1":"_7N5-4","p-lg-1":"_b-vnX","m-lg-2":"_7k7Vs","p-lg-2":"_Q2FO1","m-lg-3":"_ZTSBV","p-lg-3":"_rstCV","m-lg-4":"_juJVU","p-lg-4":"_-F4s-","m-lg-5":"_e2ifF","p-lg-5":"_U4gTc","m-lg-6":"_-4I70","p-lg-6":"_VEcMB","m-lg-7":"_LQqFi","p-lg-7":"_eX0vJ","m-lg-8":"_qPpjy","p-lg-8":"_Bhr2u","m-lg-9":"_DPuMB","p-lg-9":"_H5C3L","m-lg-10":"_1EPHM","p-lg-10":"_mVFm8","ml-lg-0":"_jLUCv","pl-lg-0":"_sdQR4","ml-lg-1":"_dO-42","pl-lg-1":"_RDmEN","ml-lg-2":"_zilrt","pl-lg-2":"_3ZlSF","ml-lg-3":"_ywVg2","pl-lg-3":"_EVjPm","ml-lg-4":"_PBq8D","pl-lg-4":"_-NNsy","ml-lg-5":"_EKt1p","pl-lg-5":"_AAU--","ml-lg-6":"_M3D3t","pl-lg-6":"_VXvIT","ml-lg-7":"_yRT7X","pl-lg-7":"_0XsPz","ml-lg-8":"_HazA-","pl-lg-8":"_JZBh1","ml-lg-9":"_BU6zu","pl-lg-9":"_UPban","ml-lg-10":"_17FL5","pl-lg-10":"_mtv0u","mr-lg-0":"_YxsrA","pr-lg-0":"_1Wmvv","mr-lg-1":"_cQiRZ","pr-lg-1":"_9oheo","mr-lg-2":"_hwBOD","pr-lg-2":"_3i51G","mr-lg-3":"_iwzVs","pr-lg-3":"_1oRFN","mr-lg-4":"_3NfjL","pr-lg-4":"_9OJfa","mr-lg-5":"_YokXX","pr-lg-5":"_owhix","mr-lg-6":"_5Grwo","pr-lg-6":"_r0hct","mr-lg-7":"_dSkGq","pr-lg-7":"_mohcn","mr-lg-8":"_NUor1","pr-lg-8":"_Sjzdu","mr-lg-9":"_Py-ID","pr-lg-9":"_cZdrq","mr-lg-10":"_Etrwm","pr-lg-10":"_YCNLZ","mt-lg-0":"_qEoXx","pt-lg-0":"_nAw0E","mt-lg-1":"_pzDlL","pt-lg-1":"_h8g2E","mt-lg-2":"_QBTy7","pt-lg-2":"_IQoFB","mt-lg-3":"_UGd6N","pt-lg-3":"_PBzO5","mt-lg-4":"_SCRsd","pt-lg-4":"_aFnaW","mt-lg-5":"_EvBB0","pt-lg-5":"_U2iJt","mt-lg-6":"_5mahS","pt-lg-6":"_bzKPx","mt-lg-7":"_E-ZPb","pt-lg-7":"_bspLi","mt-lg-8":"_UA8zu","pt-lg-8":"_3KcAQ","mt-lg-9":"_Ze8Hr","pt-lg-9":"_FKo1d","mt-lg-10":"_kIAZR","pt-lg-10":"_j2qBV","mb-lg-0":"_u8RSu","pb-lg-0":"_7uW-o","mb-lg-1":"_1MnIg","pb-lg-1":"_EeRag","mb-lg-2":"_D-pBo","pb-lg-2":"_TTAjX","mb-lg-3":"_ZldL-","pb-lg-3":"_racM9","mb-lg-4":"_bv3JQ","pb-lg-4":"_m4wR1","mb-lg-5":"_G-OW-","pb-lg-5":"_hTxUe","mb-lg-6":"_-r5uZ","pb-lg-6":"_Ri3sL","mb-lg-7":"_yay34","pb-lg-7":"_H0ybB","mb-lg-8":"_kWcyP","pb-lg-8":"_f7KWI","mb-lg-9":"_f-ap7","pb-lg-9":"_piZbL","mb-lg-10":"_7GnNB","pb-lg-10":"_8RaRH","mx-lg-0":"_E0yc1","px-lg-0":"_jXVGt","mx-lg-1":"_SLGEt","px-lg-1":"_sfpGl","mx-lg-2":"_TQdd5","px-lg-2":"_ZH4kx","mx-lg-3":"_ByYI-","px-lg-3":"_sa8fi","mx-lg-4":"_QFKsD","px-lg-4":"_S-owE","mx-lg-5":"_T-3pC","px-lg-5":"_592xL","mx-lg-6":"_nHCUC","px-lg-6":"_SHGGx","mx-lg-7":"_u8AGu","px-lg-7":"_HGDmM","mx-lg-8":"_DoojR","px-lg-8":"_-xfYS","mx-lg-9":"_a39AX","px-lg-9":"_otRdO","mx-lg-10":"_0jC0L","px-lg-10":"_o3uqZ","my-lg-0":"_fWar-","py-lg-0":"_1KGBQ","my-lg-1":"_rmTwc","py-lg-1":"_SNpLr","my-lg-2":"_nZTm1","py-lg-2":"_fo45m","my-lg-3":"_DP8Cy","py-lg-3":"_tWJ-N","my-lg-4":"_Unnfi","py-lg-4":"_TJ7sH","my-lg-5":"_xIoEe","py-lg-5":"_CH2tq","my-lg-6":"_-4iWK","py-lg-6":"_di773","my-lg-7":"_ZAyLn","py-lg-7":"_yxUoV","my-lg-8":"_AAbVi","py-lg-8":"_ijW6K","my-lg-9":"_2SOZJ","py-lg-9":"_904so","my-lg-10":"_RuT9u","py-lg-10":"_bM8I-","m-md-0":"_JzJkX","p-md-0":"_f8nh5","m-md-1":"_hBYXm","p-md-1":"_X1BU4","m-md-2":"_dnzT0","p-md-2":"_5y79V","m-md-3":"_eBoSQ","p-md-3":"_3KIpC","m-md-4":"_J4f2b","p-md-4":"_-GqF4","m-md-5":"_FaWzb","p-md-5":"_c-ssZ","m-md-6":"_R6a8a","p-md-6":"_3OwFZ","m-md-7":"_VwKx8","p-md-7":"_oICA0","m-md-8":"_D9SPT","p-md-8":"_WqmxK","m-md-9":"_K-6kd","p-md-9":"_RNgLg","m-md-10":"_X2S0Q","p-md-10":"_dUN9U","ml-md-0":"_KI-v9","pl-md-0":"_J-z-m","ml-md-1":"_40NhZ","pl-md-1":"_dwk56","ml-md-2":"_-gtX1","pl-md-2":"_M-jkC","ml-md-3":"_bbVwf","pl-md-3":"_RzC-C","ml-md-4":"_QmHWn","pl-md-4":"_2Lg6Z","ml-md-5":"_TwW16","pl-md-5":"_NvcKj","ml-md-6":"_wxYmK","pl-md-6":"_Ay-nQ","ml-md-7":"_7FRbu","pl-md-7":"_zQusT","ml-md-8":"_f0-0U","pl-md-8":"_rE4oG","ml-md-9":"_8sF7X","pl-md-9":"_RPdXC","ml-md-10":"_-3o3f","pl-md-10":"_JN4N-","mr-md-0":"_5uGyZ","pr-md-0":"_sHCfS","mr-md-1":"_T-APd","pr-md-1":"_EWggr","mr-md-2":"_-IV1z","pr-md-2":"_Mj-hm","mr-md-3":"_W4jcg","pr-md-3":"_rACeA","mr-md-4":"_NVp7l","pr-md-4":"_6LfUe","mr-md-5":"_VyxVE","pr-md-5":"_edWIM","mr-md-6":"_FZQF6","pr-md-6":"_LJpMl","mr-md-7":"_xwZ6q","pr-md-7":"_YflPE","mr-md-8":"_RiPLi","pr-md-8":"_HZNIr","mr-md-9":"_2ZsDj","pr-md-9":"_XBBrF","mr-md-10":"_-kG-G","pr-md-10":"_co3mI","mt-md-0":"_e6IV0","pt-md-0":"_eLP-0","mt-md-1":"_27KXx","pt-md-1":"_gQ2-y","mt-md-2":"_L6-1Q","pt-md-2":"_x7jaE","mt-md-3":"_r5yZl","pt-md-3":"_jTIZh","mt-md-4":"_TxxTT","pt-md-4":"_znNzQ","mt-md-5":"_aPml3","pt-md-5":"_o-WiU","mt-md-6":"_ePcku","pt-md-6":"_7PW3g","mt-md-7":"_qOy4h","pt-md-7":"_czEFY","mt-md-8":"_C5QNJ","pt-md-8":"_LXyGu","mt-md-9":"_BzCq8","pt-md-9":"_j6x7Q","mt-md-10":"_RyoZo","pt-md-10":"_HO6RH","mb-md-0":"_dBqjR","pb-md-0":"_Vtnl-","mb-md-1":"_4CIBM","pb-md-1":"_nkuIR","mb-md-2":"_jioqc","pb-md-2":"_KVlPp","mb-md-3":"_NVp7e","pb-md-3":"_51YgW","mb-md-4":"_6ZjBo","pb-md-4":"_5ewFY","mb-md-5":"_ttOxi","pb-md-5":"_VLqqB","mb-md-6":"_Vl1FM","pb-md-6":"_lj2o-","mb-md-7":"_fY9Hi","pb-md-7":"_vdqU0","mb-md-8":"_MBU95","pb-md-8":"_z-gSw","mb-md-9":"_Wr9dI","pb-md-9":"_D1Q7Q","mb-md-10":"_-resl","pb-md-10":"_Jamfb","mx-md-0":"_0r9rS","px-md-0":"_epgof","mx-md-1":"_aYYOb","px-md-1":"_g6u4x","mx-md-2":"_v6Jsi","px-md-2":"_e7lpx","mx-md-3":"_B5OpT","px-md-3":"_IJdST","mx-md-4":"_Vgq7O","px-md-4":"_q2tQ3","mx-md-5":"_udCxk","px-md-5":"_dkBwz","mx-md-6":"_HAAdk","px-md-6":"_gxcpD","mx-md-7":"_-wAGl","px-md-7":"_PBj8s","mx-md-8":"_51YzX","px-md-8":"_Ht55U","mx-md-9":"_UaNNS","px-md-9":"_A3qbp","mx-md-10":"_O9ir-","px-md-10":"_2jJOG","my-md-0":"_p6EfS","py-md-0":"_8FGSM","my-md-1":"_T6eYc","py-md-1":"_Jrh0m","my-md-2":"_oxohh","py-md-2":"_DTd2y","my-md-3":"_iGc8i","py-md-3":"_jqXbJ","my-md-4":"_wCkrO","py-md-4":"_4p1cz","my-md-5":"_m1Dhe","py-md-5":"_UFngr","my-md-6":"_FdWqj","py-md-6":"_utySi","my-md-7":"_TsKhD","py-md-7":"_8aght","my-md-8":"_H2tbJ","py-md-8":"_mX8dL","my-md-9":"_YP8V8","py-md-9":"_GEd1x","my-md-10":"_qnAfn","py-md-10":"_3MK3a","m-xl-0":"_QUeDl","p-xl-0":"_tpnY6","m-xl-1":"_JhTnG","p-xl-1":"_leasc","m-xl-2":"_rj70q","p-xl-2":"_nmUas","m-xl-3":"_SH7Mw","p-xl-3":"_2sLhA","m-xl-4":"_WKBLF","p-xl-4":"_JTlZn","m-xl-5":"_keccz","p-xl-5":"_W2L9n","m-xl-6":"_MmHtB","p-xl-6":"_16QWL","m-xl-7":"_qoXt8","p-xl-7":"_aZTjp","m-xl-8":"_Gl1CI","p-xl-8":"_u033S","m-xl-9":"_fgyK-","p-xl-9":"_gWQMQ","m-xl-10":"_1zthQ","p-xl-10":"_jYgaz","ml-xl-0":"_Gc0yF","pl-xl-0":"_7r0qa","ml-xl-1":"_riQOx","pl-xl-1":"_ZOf2r","ml-xl-2":"_aqpam","pl-xl-2":"_Kzewg","ml-xl-3":"_riGnY","pl-xl-3":"_fImnr","ml-xl-4":"_Spb-1","pl-xl-4":"_xqk-P","ml-xl-5":"_5ZrWS","pl-xl-5":"_KEqQd","ml-xl-6":"_6cdvz","pl-xl-6":"_RjL-8","ml-xl-7":"_hfyi5","pl-xl-7":"_-xSML","ml-xl-8":"_eHDDu","pl-xl-8":"_iDidv","ml-xl-9":"_Gg4Fk","pl-xl-9":"_fYSK3","ml-xl-10":"_1V3MM","pl-xl-10":"_4jnhK","mr-xl-0":"_8fnBs","pr-xl-0":"_Kemkd","mr-xl-1":"_4ox8d","pr-xl-1":"_zG2Y2","mr-xl-2":"_Pl4X2","pr-xl-2":"_EZpb9","mr-xl-3":"_efgC0","pr-xl-3":"_6hd7x","mr-xl-4":"_rp8M9","pr-xl-4":"_nsRMj","mr-xl-5":"_ayyUE","pr-xl-5":"_BHXMH","mr-xl-6":"_Ez0-c","pr-xl-6":"_xTS9o","mr-xl-7":"_KlyJI","pr-xl-7":"_w3-5z","mr-xl-8":"_onnmv","pr-xl-8":"_aQYpF","mr-xl-9":"_D4mrX","pr-xl-9":"_-MGmg","mr-xl-10":"_KmLe8","pr-xl-10":"_rxxtP","mt-xl-0":"_0-1Kw","pt-xl-0":"_jVAPE","mt-xl-1":"_dO4nc","pt-xl-1":"_oFjXt","mt-xl-2":"_njinL","pt-xl-2":"_EVcqW","mt-xl-3":"_k7EwU","pt-xl-3":"_oALYA","mt-xl-4":"_SSrqv","pt-xl-4":"_8ZIWU","mt-xl-5":"_PXga1","pt-xl-5":"_ewSdF","mt-xl-6":"_0hKMy","pt-xl-6":"_fmLlw","mt-xl-7":"_aBbeO","pt-xl-7":"_Ghd-T","mt-xl-8":"_QILjg","pt-xl-8":"_4401M","mt-xl-9":"_mdFN4","pt-xl-9":"_uBjA3","mt-xl-10":"_l3TPU","pt-xl-10":"_hIKVS","mb-xl-0":"_2Et8-","pb-xl-0":"_uBGMl","mb-xl-1":"_AnrEX","pb-xl-1":"_-PMBv","mb-xl-2":"_cr4lU","pb-xl-2":"_BVCap","mb-xl-3":"_PgCvP","pb-xl-3":"_69b-5","mb-xl-4":"_x5odK","pb-xl-4":"_LzoYk","mb-xl-5":"_3q-dE","pb-xl-5":"_DXCCv","mb-xl-6":"_I8Qbz","pb-xl-6":"_wK-Lg","mb-xl-7":"_NXT2E","pb-xl-7":"_hw62n","mb-xl-8":"_w5tOT","pb-xl-8":"_KA9xk","mb-xl-9":"_B5jk4","pb-xl-9":"_N5trL","mb-xl-10":"_JU9c5","pb-xl-10":"_kP-VE","mx-xl-0":"_jgBYj","px-xl-0":"_iLny2","mx-xl-1":"_1PpJT","px-xl-1":"_eAdDk","mx-xl-2":"_v1kJm","px-xl-2":"_hU50M","mx-xl-3":"_L1JqU","px-xl-3":"_lGvGI","mx-xl-4":"_KNNj2","px-xl-4":"_6-Kgj","mx-xl-5":"_r9t8u","px-xl-5":"_pI6ok","mx-xl-6":"_YO3KF","px-xl-6":"_LIjtn","mx-xl-7":"_Yz-3Z","px-xl-7":"_7xWar","mx-xl-8":"_NEAsT","px-xl-8":"_KSLjS","mx-xl-9":"_XqTby","px-xl-9":"_y5sVK","mx-xl-10":"_GysTi","px-xl-10":"_udCRM","my-xl-0":"_iWpWS","py-xl-0":"_cyc8U","my-xl-1":"_IcUiN","py-xl-1":"_bfKBO","my-xl-2":"_IFTOa","py-xl-2":"_sXWH4","my-xl-3":"_TXATm","py-xl-3":"_Vt5Ze","my-xl-4":"_GLPso","py-xl-4":"_dI2DM","my-xl-5":"_twkBw","py-xl-5":"_m7dMy","my-xl-6":"_a-KcP","py-xl-6":"_dLwS8","my-xl-7":"_qkPb4","py-xl-7":"_uZaN7","my-xl-8":"_2btRT","py-xl-8":"_qsAt5","my-xl-9":"_LpPEh","py-xl-9":"_v1Rtf","my-xl-10":"_xKXEK","py-xl-10":"_pZt9W","background-shine":"_K7sQH","path":"_ko8i0","line":"_uhBI-","skeleton":"_tfiqH","skeleton-animate":"_haT-0","skeleton-dark":"_ZpubN","skeleton-dark-animate":"_BVbU1","skeleton-transparent":"_p-CoM","skeleton-transparent-animate":"_YElIQ","semi-transparent":"_wSCsK","no-margins":"_lNgTM","dots":"_igFzN","colored":"_iCiK-","small":"_zvmsC","extra-small":"_6tLmp","align-left":"_jJMP1","align-right":"_jpWFr"};
1161
+ var styles = {"container":"_a5RSj","m-0":"_wcoyj","p-0":"_Rd5sE","m-1":"_vAsxv","p-1":"_KZ14Z","m-2":"_Bvk20","p-2":"_Z7fhL","m-3":"_ZqDCi","p-3":"_CiGc9","m-4":"_8JK-L","p-4":"_FadoA","m-5":"_baCle","p-5":"_cvJqX","m-6":"_P3lUT","p-6":"_ZmGGH","m-7":"_5Tnff","p-7":"_-t7z9","m-8":"_1JxUQ","p-8":"_EATOh","m-9":"_pJGV0","p-9":"_B762d","m-10":"_Z3rGU","p-10":"_0ULM0","ml-0":"_ZSfG7","pl-0":"_hjKq0","ml-1":"_srwbU","pl-1":"_oz-sG","ml-2":"_RnILi","pl-2":"_-nAjZ","ml-3":"_lges5","pl-3":"_AwVsn","ml-4":"_p4arL","pl-4":"_upAfC","ml-5":"_-iEnG","pl-5":"_bqApa","ml-6":"_uF0xd","pl-6":"_WUUFo","ml-7":"_eXFZs","pl-7":"_ZforM","ml-8":"_2AA5o","pl-8":"_u6bF0","ml-9":"_19IxL","pl-9":"_vmLg6","ml-10":"_eyqFK","pl-10":"_mr36J","mr-0":"_6RpFz","pr-0":"_fgnzi","mr-1":"_fBjrA","pr-1":"_QrC2Y","mr-2":"_0Y6RC","pr-2":"_5kZkr","mr-3":"_iaZj-","pr-3":"_A-IQ7","mr-4":"_zBHHn","pr-4":"_pHQ4t","mr-5":"_1JTCi","pr-5":"_ODvHf","mr-6":"_n6Enr","pr-6":"_XNdBl","mr-7":"_YfaVy","pr-7":"_ZfZDh","mr-8":"_le3sp","pr-8":"_K1rvN","mr-9":"_mL6UV","pr-9":"_76mZn","mr-10":"_fo-sf","pr-10":"_xvsK1","mt-0":"_1uBdK","pt-0":"_30qg7","mt-1":"_NKlWd","pt-1":"_3yj99","mt-2":"_lLyiG","pt-2":"_GsXqc","mt-3":"_zC55o","pt-3":"_3OZTc","mt-4":"_v1VXO","pt-4":"_sFrdR","mt-5":"_qbBFx","pt-5":"_DQrF8","mt-6":"_dJG8P","pt-6":"_Zxte7","mt-7":"_sUtkp","pt-7":"_9B1r5","mt-8":"_Qrnld","pt-8":"_7xBV7","mt-9":"_OPKw2","pt-9":"_cXhnD","mt-10":"_m5k36","pt-10":"_b9nMR","mb-0":"_7AyaR","pb-0":"_u0vFs","mb-1":"_ivpnr","pb-1":"_1dkPf","mb-2":"_D8KfL","pb-2":"_wzuIB","mb-3":"_zwh5E","pb-3":"_rT8wS","mb-4":"_wpLh9","pb-4":"_AGvn8","mb-5":"_-phDB","pb-5":"_r4HWg","mb-6":"_RZI7I","pb-6":"_-t4Gs","mb-7":"_Vw-z1","pb-7":"_qwD1B","mb-8":"_f3nKh","pb-8":"_Sk1Fn","mb-9":"_2MDAw","pb-9":"_jZbwv","mb-10":"_gRDI3","pb-10":"_W7OVZ","mx-0":"_I6mmv","px-0":"_BVRG5","mx-1":"_b7fTJ","px-1":"_bZf6u","mx-2":"_FoGd8","px-2":"_-vX3t","mx-3":"_0H3Cj","loading-dots":"_pnWN9","big":"_k0j0g","dot":"_9LXS6","px-3":"_ggifM","mx-4":"_leP-v","px-4":"_7Kcun","mx-5":"_sBxud","px-5":"_oJO7X","mx-6":"_F-Una","px-6":"_Bl-A8","mx-7":"_NVWrT","px-7":"_Bn6vR","mx-8":"_OK9GD","px-8":"_iv1v2","mx-9":"_WVtLI","px-9":"_ntW3v","mx-10":"_21M1-","px-10":"_BjXo-","my-0":"_3v8p4","py-0":"_EBmV-","my-1":"_DcOh5","py-1":"_udCfN","my-2":"_Lk0RK","py-2":"_wIENK","my-3":"_nsOf5","py-3":"_No-oK","my-4":"_L1ycy","py-4":"_42DgQ","my-5":"_3bZSh","py-5":"_XjTMT","my-6":"_Ty-GG","py-6":"_7Dr5E","my-7":"_PILBF","py-7":"_vyvsk","my-8":"_AkmkO","py-8":"_X0xg-","my-9":"_VSxcf","py-9":"_Hq-yp","my-10":"_FxwFR","py-10":"_BnN2G","m-sm-0":"_EZHgz","p-sm-0":"_oKPqX","m-sm-1":"_gdysh","p-sm-1":"_-7KK8","m-sm-2":"_BLBqZ","p-sm-2":"_IgrmD","m-sm-3":"_zbrA7","p-sm-3":"_eimPJ","m-sm-4":"_7RaaP","p-sm-4":"_0-Cvi","m-sm-5":"_PhCOs","p-sm-5":"_CIKFA","m-sm-6":"_8WC3P","p-sm-6":"_2FqT5","m-sm-7":"_D7sDK","p-sm-7":"_L3EpN","m-sm-8":"_mG6-A","p-sm-8":"_D2Gx9","m-sm-9":"_2tGFi","p-sm-9":"_8n6VA","m-sm-10":"_G-MMA","p-sm-10":"_pgJzb","ml-sm-0":"_BF125","pl-sm-0":"_81k6q","ml-sm-1":"_JSywC","pl-sm-1":"_1eoeN","ml-sm-2":"_q5cSf","pl-sm-2":"_A6Li5","ml-sm-3":"_-7C1-","pl-sm-3":"_lBIcx","ml-sm-4":"_bvj1N","pl-sm-4":"_SQmLb","ml-sm-5":"_pwy33","pl-sm-5":"_iuqDu","ml-sm-6":"_CNiYb","pl-sm-6":"_tQ2J-","ml-sm-7":"_Zuec-","pl-sm-7":"_iJF5q","ml-sm-8":"_lP-ls","pl-sm-8":"_1xIwn","ml-sm-9":"_Jld-6","pl-sm-9":"_pfOVT","ml-sm-10":"_TGfAU","pl-sm-10":"_MYgNP","mr-sm-0":"_CEiPO","pr-sm-0":"_rZ5kD","mr-sm-1":"_-bdjz","pr-sm-1":"_nRBRL","mr-sm-2":"_17O3E","pr-sm-2":"_uBaUj","mr-sm-3":"_5oO1d","pr-sm-3":"_jQWXm","mr-sm-4":"_peO4Y","pr-sm-4":"_P2f3n","mr-sm-5":"_AUc3q","pr-sm-5":"_7TR99","mr-sm-6":"_e3d5h","pr-sm-6":"_QqPl1","mr-sm-7":"_Yc1cR","pr-sm-7":"_5fd5H","mr-sm-8":"_z4g3-","pr-sm-8":"_gY3T9","mr-sm-9":"_P9chP","pr-sm-9":"_G4k6A","mr-sm-10":"_QWMD2","pr-sm-10":"_2POWv","mt-sm-0":"_xYS0m","pt-sm-0":"_gYD3b","mt-sm-1":"_08rCY","pt-sm-1":"_UsP-z","mt-sm-2":"_HWQec","pt-sm-2":"_cjIgZ","mt-sm-3":"_gZV20","pt-sm-3":"_zJZJm","mt-sm-4":"_4FE5W","pt-sm-4":"_VpJhv","mt-sm-5":"_eu88H","pt-sm-5":"_V7qwC","mt-sm-6":"_09LyL","pt-sm-6":"_n8bba","mt-sm-7":"_q-ASs","pt-sm-7":"_3b9S8","mt-sm-8":"_iTxDv","pt-sm-8":"_--Hdk","mt-sm-9":"_OaVE-","pt-sm-9":"_cd-UP","mt-sm-10":"_ZIr-H","pt-sm-10":"_6jYkb","mb-sm-0":"_YgN23","pb-sm-0":"_F8F6A","mb-sm-1":"_4QH8u","pb-sm-1":"_A2I8v","mb-sm-2":"_jrZxh","pb-sm-2":"_2VL1m","mb-sm-3":"_IB8uX","pb-sm-3":"_meger","mb-sm-4":"_-gCVy","pb-sm-4":"_R-qMm","mb-sm-5":"_YwvXh","pb-sm-5":"_pyu5v","mb-sm-6":"_qwhTX","pb-sm-6":"_l61nc","mb-sm-7":"_0KfeR","pb-sm-7":"_YXuNM","mb-sm-8":"_75fJr","pb-sm-8":"_jp-Qe","mb-sm-9":"_V0wM-","pb-sm-9":"_vMKpc","mb-sm-10":"_sxEY8","pb-sm-10":"_k2mOD","mx-sm-0":"_qPF9i","px-sm-0":"_cl18e","mx-sm-1":"_LvMUO","px-sm-1":"_RcIbD","mx-sm-2":"_xLMK5","px-sm-2":"_GCL1S","mx-sm-3":"_t0q4o","px-sm-3":"_cuiW8","mx-sm-4":"_pHjdd","px-sm-4":"_LDu1N","mx-sm-5":"_cYpLd","px-sm-5":"_24Yji","mx-sm-6":"_pXCM6","px-sm-6":"_uoSDI","mx-sm-7":"_qbXoQ","px-sm-7":"_0RlFx","mx-sm-8":"_3f-s3","px-sm-8":"_xAS-y","mx-sm-9":"_vx3dZ","px-sm-9":"_ndXm6","mx-sm-10":"_6lFsZ","px-sm-10":"_EZ6Qr","my-sm-0":"_0t-Cg","py-sm-0":"_N3sbI","my-sm-1":"_jdmVi","py-sm-1":"_GlMKb","my-sm-2":"_yFRs8","py-sm-2":"_LNRZQ","my-sm-3":"_qSuwF","py-sm-3":"_ON3vd","my-sm-4":"_1h6pX","py-sm-4":"_TZg0h","my-sm-5":"_vT295","py-sm-5":"_J1zu8","my-sm-6":"_7LuwF","py-sm-6":"_qbbdP","my-sm-7":"_9vKuY","py-sm-7":"_C9gzg","my-sm-8":"_Nx1-S","py-sm-8":"_8lmEZ","my-sm-9":"_LxGxx","py-sm-9":"_3y4jy","my-sm-10":"_61y0C","py-sm-10":"_fxmBa","m-lg-0":"_PJydR","p-lg-0":"_3o1cd","m-lg-1":"_MAdi8","p-lg-1":"_JDc1V","m-lg-2":"_pEH2Q","p-lg-2":"_Ic9tL","m-lg-3":"_P6cGt","p-lg-3":"_nzx-g","m-lg-4":"_9bH-j","p-lg-4":"_KdZTF","m-lg-5":"_hxjaE","p-lg-5":"_LDamm","m-lg-6":"_xXtVI","p-lg-6":"_ZWhTL","m-lg-7":"_mPnVe","p-lg-7":"_lJnBT","m-lg-8":"_J-MQA","p-lg-8":"_MGs60","m-lg-9":"_ixlkP","p-lg-9":"_Lru1O","m-lg-10":"_eH6ht","p-lg-10":"_ugZzQ","ml-lg-0":"_6z3OE","pl-lg-0":"_PDwaH","ml-lg-1":"_GMcN9","pl-lg-1":"_NoDTB","ml-lg-2":"_PQ5AQ","pl-lg-2":"_8-Pu6","ml-lg-3":"_PktVo","pl-lg-3":"_JTpEZ","ml-lg-4":"_zIcyb","pl-lg-4":"_e4YYS","ml-lg-5":"_HrlcA","pl-lg-5":"_cwG3s","ml-lg-6":"_Xf7Wv","pl-lg-6":"_XYe-E","ml-lg-7":"_vnGAT","pl-lg-7":"_NnScU","ml-lg-8":"_9z7Tj","pl-lg-8":"_DDEn1","ml-lg-9":"_sxSQp","pl-lg-9":"_-r39c","ml-lg-10":"_kppNg","pl-lg-10":"_1mgTz","mr-lg-0":"_WtS6h","pr-lg-0":"_NKNU9","mr-lg-1":"_kxaOQ","pr-lg-1":"_8OvSK","mr-lg-2":"_bTQt8","pr-lg-2":"_yQerd","mr-lg-3":"_f7H9P","pr-lg-3":"_Kwfoa","mr-lg-4":"_lkF5d","pr-lg-4":"_b7tIe","mr-lg-5":"_H4e5a","pr-lg-5":"_pxwBt","mr-lg-6":"_I81Hq","pr-lg-6":"_1Xwlf","mr-lg-7":"_gtO-Y","pr-lg-7":"_vjm3Z","mr-lg-8":"_ZfEr1","pr-lg-8":"_je0MD","mr-lg-9":"_h43Co","pr-lg-9":"_Lnbh5","mr-lg-10":"_HoaFo","pr-lg-10":"_3puFA","mt-lg-0":"_a7pDC","pt-lg-0":"_-URo7","mt-lg-1":"_Ot-U1","pt-lg-1":"_rMvMf","mt-lg-2":"_95ooz","pt-lg-2":"_vkEgW","mt-lg-3":"_9XqX5","pt-lg-3":"_b-oGK","mt-lg-4":"_eYL6E","pt-lg-4":"_zgUGu","mt-lg-5":"_BqCaM","pt-lg-5":"_Y9PL4","mt-lg-6":"_0aOPb","pt-lg-6":"_nvMum","mt-lg-7":"_-pNQS","pt-lg-7":"_funa7","mt-lg-8":"_sDweY","pt-lg-8":"_S1hmu","mt-lg-9":"_Y4BpR","pt-lg-9":"_J3203","mt-lg-10":"_Jm-dV","pt-lg-10":"_0WSnk","mb-lg-0":"_4uWrE","pb-lg-0":"_qy0mb","mb-lg-1":"_jUNMm","pb-lg-1":"_pUTOt","mb-lg-2":"_aGqhb","pb-lg-2":"_xAKUw","mb-lg-3":"_kado5","pb-lg-3":"_htLgL","mb-lg-4":"_mWWU1","pb-lg-4":"_gqGWe","mb-lg-5":"_ceycQ","pb-lg-5":"_RzNIh","mb-lg-6":"_VLMG4","pb-lg-6":"_-8-Aj","mb-lg-7":"_HBnRW","pb-lg-7":"_ZsIEk","mb-lg-8":"_bj2r5","pb-lg-8":"_cBnkL","mb-lg-9":"_w3001","pb-lg-9":"_Kua-7","mb-lg-10":"_wZKsF","pb-lg-10":"_GX-Wb","mx-lg-0":"_-G50w","px-lg-0":"_OTPQl","mx-lg-1":"_JJ9DD","px-lg-1":"_jedSl","mx-lg-2":"_n9zl3","px-lg-2":"_Cg-Eq","mx-lg-3":"_6ZhL3","px-lg-3":"_0oPYT","mx-lg-4":"_H9sE1","px-lg-4":"_aV3U2","mx-lg-5":"_Y2BNn","px-lg-5":"_EzRHI","mx-lg-6":"_fp9jU","px-lg-6":"_wghWL","mx-lg-7":"_zB5Qv","px-lg-7":"_gclTH","mx-lg-8":"_Qxq2x","px-lg-8":"_M7akr","mx-lg-9":"_Vfhs-","px-lg-9":"_Rv7m-","mx-lg-10":"_lni3U","px-lg-10":"_gdVVu","my-lg-0":"_rMuza","py-lg-0":"_MZopi","my-lg-1":"_Thq10","py-lg-1":"_BXQnr","my-lg-2":"_lHRe-","py-lg-2":"_6MiWj","my-lg-3":"_-vobr","py-lg-3":"_xtsGY","my-lg-4":"_m2hen","py-lg-4":"_-069Y","my-lg-5":"_nTHzp","py-lg-5":"_r4pes","my-lg-6":"_LTkTV","py-lg-6":"_13TOF","my-lg-7":"_Em859","py-lg-7":"_mJzVF","my-lg-8":"_T8EVh","py-lg-8":"_h2ol5","my-lg-9":"_T-LZJ","py-lg-9":"_QIrnZ","my-lg-10":"_EY0q7","py-lg-10":"_hvU2E","m-md-0":"_u8Not","p-md-0":"_PVgyV","m-md-1":"_y-q4l","p-md-1":"_7X2x6","m-md-2":"_r3IGF","p-md-2":"_abaFH","m-md-3":"_rH0Ca","p-md-3":"_m-V0R","m-md-4":"_NQj-k","p-md-4":"_xjGzA","m-md-5":"_41oza","p-md-5":"_cgf0Z","m-md-6":"_lelHI","p-md-6":"_2C8Oa","m-md-7":"_w1Eil","p-md-7":"_EtEzw","m-md-8":"_Q8a3D","p-md-8":"_5nsxA","m-md-9":"_LzOqJ","p-md-9":"_7LEzr","m-md-10":"_CRNVR","p-md-10":"_ClNNV","ml-md-0":"_3abXz","pl-md-0":"_7BRiC","ml-md-1":"_Jbe0V","pl-md-1":"_Ok-KV","ml-md-2":"_5SO4-","pl-md-2":"_IvJ88","ml-md-3":"_NWLcP","pl-md-3":"_XASwl","ml-md-4":"_La-jA","pl-md-4":"_M8vz7","ml-md-5":"_4UZJ3","pl-md-5":"_ikRMN","ml-md-6":"_GpxKA","pl-md-6":"_-vp4I","ml-md-7":"_qZisY","pl-md-7":"_UspU5","ml-md-8":"_xTqIg","pl-md-8":"_8LLNG","ml-md-9":"_u3Wi6","pl-md-9":"_yukVA","ml-md-10":"_BJ3Kb","pl-md-10":"_Ncx33","mr-md-0":"_-dCKD","pr-md-0":"_p4Xdb","mr-md-1":"_DZXj3","pr-md-1":"_YZLPN","mr-md-2":"_IEATr","pr-md-2":"_OGWz-","mr-md-3":"_UxMFq","pr-md-3":"_qMmI8","mr-md-4":"_KEt4t","pr-md-4":"_nLevO","mr-md-5":"_AMVPM","pr-md-5":"_3m10o","mr-md-6":"_fzrrj","pr-md-6":"_Wbjjj","mr-md-7":"_mZWrU","pr-md-7":"_mqIEB","mr-md-8":"_5p3E5","pr-md-8":"_NyrXd","mr-md-9":"_gez8y","pr-md-9":"_qLaJ8","mr-md-10":"_TR-zd","pr-md-10":"_SqjX-","mt-md-0":"_Okpug","pt-md-0":"_xIGF1","mt-md-1":"_kkttT","pt-md-1":"_6Fntk","mt-md-2":"_jjt3V","pt-md-2":"_MBCLj","mt-md-3":"_AcRpn","pt-md-3":"_9e4N3","mt-md-4":"_TEYLB","pt-md-4":"_G-b2b","mt-md-5":"_ADYmJ","pt-md-5":"_-PW2W","mt-md-6":"_IiBSh","pt-md-6":"_oOMKv","mt-md-7":"_LzMKR","pt-md-7":"_P93Fk","mt-md-8":"_ZPChR","pt-md-8":"_IjZLd","mt-md-9":"_OYWyj","pt-md-9":"_6VDq-","mt-md-10":"_NFUMl","pt-md-10":"_9N5Rs","mb-md-0":"_KNEZM","pb-md-0":"_dlRtG","mb-md-1":"_2TJCJ","pb-md-1":"_FYJz-","mb-md-2":"_p5q4o","pb-md-2":"_W20R5","mb-md-3":"_QMtNI","pb-md-3":"_X4ghG","mb-md-4":"_ROsHu","pb-md-4":"_LLz3c","mb-md-5":"_FKlov","pb-md-5":"_qQje5","mb-md-6":"_zHdHt","pb-md-6":"_7vH68","mb-md-7":"_5-25V","pb-md-7":"_a5Jzs","mb-md-8":"_9NPzr","pb-md-8":"_NpZZI","mb-md-9":"_F5182","pb-md-9":"_2SM3y","mb-md-10":"_R3bvz","pb-md-10":"_Sop9H","mx-md-0":"_OUA4d","px-md-0":"_s-0Qy","mx-md-1":"_cBeVb","px-md-1":"_34ZBT","mx-md-2":"_-dnuU","px-md-2":"_0-UrT","mx-md-3":"_CewFh","px-md-3":"_ZrFGb","mx-md-4":"_5Cvub","px-md-4":"_9CpfN","mx-md-5":"_O1iRv","px-md-5":"_dnUx0","mx-md-6":"_QmgAB","px-md-6":"_vP8Uq","mx-md-7":"_PcZ9w","px-md-7":"_5l4s3","mx-md-8":"_isOXv","px-md-8":"_cvHBA","mx-md-9":"_LIRJ0","px-md-9":"_09Gju","mx-md-10":"_b-TCB","px-md-10":"_5UoX8","my-md-0":"_wrYvU","py-md-0":"_Fwd2A","my-md-1":"_vBwvs","py-md-1":"_vl1f-","my-md-2":"_7g5va","py-md-2":"_D0JS-","my-md-3":"_8DN0N","py-md-3":"_qvNWl","my-md-4":"_o5Mnp","py-md-4":"_rFfbU","my-md-5":"_7XZDH","py-md-5":"_1B0Rr","my-md-6":"_s09ut","py-md-6":"_jnQRw","my-md-7":"_PgL1b","py-md-7":"_T4779","my-md-8":"_R0d0D","py-md-8":"_Fkri-","my-md-9":"_FM-XK","py-md-9":"_H-snR","my-md-10":"_Z49JP","py-md-10":"_01G-F","m-xl-0":"_H4Jyh","p-xl-0":"_WMtq9","m-xl-1":"_FeJPz","p-xl-1":"_00t3r","m-xl-2":"_svLno","p-xl-2":"_2C22I","m-xl-3":"_T5qYA","p-xl-3":"_dcbn0","m-xl-4":"_Xl89-","p-xl-4":"_Ctf-y","m-xl-5":"_ZWihS","p-xl-5":"_Lzig2","m-xl-6":"_jljvY","p-xl-6":"_X1owU","m-xl-7":"_l1myf","p-xl-7":"_T1fTP","m-xl-8":"_FWU16","p-xl-8":"_R2T50","m-xl-9":"_2TtzQ","p-xl-9":"_-142y","m-xl-10":"_975wG","p-xl-10":"_DPori","ml-xl-0":"_9Zc9q","pl-xl-0":"_On2x0","ml-xl-1":"_IryvS","pl-xl-1":"_J2DXA","ml-xl-2":"_S7cyp","pl-xl-2":"_YxNk9","ml-xl-3":"_6eyqg","pl-xl-3":"_cwyGU","ml-xl-4":"_TbIDB","pl-xl-4":"_JKpl8","ml-xl-5":"_P17BD","pl-xl-5":"_w8ccI","ml-xl-6":"_fUJPM","pl-xl-6":"_mgqKZ","ml-xl-7":"_p-Fn9","pl-xl-7":"_eMF8n","ml-xl-8":"_VO2-y","pl-xl-8":"_O9n-E","ml-xl-9":"_wqX4W","pl-xl-9":"_wDG35","ml-xl-10":"_-TNE-","pl-xl-10":"_jyfgf","mr-xl-0":"_9aQeC","pr-xl-0":"_zWCV0","mr-xl-1":"_vL8LJ","pr-xl-1":"_yA6nk","mr-xl-2":"_ZkYxH","pr-xl-2":"_-LN7c","mr-xl-3":"_WtPxc","pr-xl-3":"_Yn0F0","mr-xl-4":"_M1pzN","pr-xl-4":"_zX1qM","mr-xl-5":"_HWX7s","pr-xl-5":"_0jJWY","mr-xl-6":"_cG-JL","pr-xl-6":"_o2-cg","mr-xl-7":"_g0V5o","pr-xl-7":"_seBWS","mr-xl-8":"_1Rg0L","pr-xl-8":"_uZxYI","mr-xl-9":"_DJD2r","pr-xl-9":"_WXY42","mr-xl-10":"_-EWpt","pr-xl-10":"_W-0Oq","mt-xl-0":"_A3mxM","pt-xl-0":"_mG8-q","mt-xl-1":"_eSV7Q","pt-xl-1":"_9SJkd","mt-xl-2":"_mdspA","pt-xl-2":"_GloWk","mt-xl-3":"_Fn9WR","pt-xl-3":"_l5z5Q","mt-xl-4":"_J5EuO","pt-xl-4":"_z4jGH","mt-xl-5":"_SjIc3","pt-xl-5":"_inlrN","mt-xl-6":"_9iy8O","pt-xl-6":"_FGdNq","mt-xl-7":"_DNLb-","pt-xl-7":"_FDvwW","mt-xl-8":"_cB8Ua","pt-xl-8":"_sFRzN","mt-xl-9":"_iFCES","pt-xl-9":"_M8U3T","mt-xl-10":"_zrBn9","pt-xl-10":"_kYhdD","mb-xl-0":"_AVjLW","pb-xl-0":"_S2OiP","mb-xl-1":"_vnN5p","pb-xl-1":"_ukgJ7","mb-xl-2":"_wZjwy","pb-xl-2":"_rINJ4","mb-xl-3":"_MFAs1","pb-xl-3":"_BjtEQ","mb-xl-4":"_72dvy","pb-xl-4":"_bCnbX","mb-xl-5":"_Uyt6r","pb-xl-5":"_F3Ibd","mb-xl-6":"_iBLUD","pb-xl-6":"_yjY5Y","mb-xl-7":"_6TfYx","pb-xl-7":"_QdVWm","mb-xl-8":"_p-cIL","pb-xl-8":"_saIeH","mb-xl-9":"_Z3PUh","pb-xl-9":"_f8cy7","mb-xl-10":"_ndw2F","pb-xl-10":"_Yxkus","mx-xl-0":"_Bb6PX","px-xl-0":"_M5EOJ","mx-xl-1":"_iWwKY","px-xl-1":"_nWXZF","mx-xl-2":"_OCB5d","px-xl-2":"_GIqDO","mx-xl-3":"_mskG2","px-xl-3":"_-TVSP","mx-xl-4":"_rp-dc","px-xl-4":"_rfQsy","mx-xl-5":"_FgYNJ","px-xl-5":"_yA-K0","mx-xl-6":"_KJ12G","px-xl-6":"_gmhRk","mx-xl-7":"_XF8NS","px-xl-7":"_C0zhm","mx-xl-8":"_rOBd5","px-xl-8":"_FZf4w","mx-xl-9":"_GosX1","px-xl-9":"_zvpad","mx-xl-10":"_uU6kY","px-xl-10":"_XfRJ5","my-xl-0":"_zhez-","py-xl-0":"_-Dum7","my-xl-1":"_QvfIQ","py-xl-1":"_66V5-","my-xl-2":"_e84Sk","py-xl-2":"_pOej1","my-xl-3":"_uv8an","py-xl-3":"_6iY-g","my-xl-4":"_Ur6W4","py-xl-4":"_JPq7T","my-xl-5":"_3GKlh","py-xl-5":"_Gcnsl","my-xl-6":"_JrBH1","py-xl-6":"_IP0ND","my-xl-7":"_7BzpU","py-xl-7":"_BIUqI","my-xl-8":"_mZ-p0","py-xl-8":"_Sdn5j","my-xl-9":"_P3V1N","py-xl-9":"_Z9lbF","my-xl-10":"_VAfcF","py-xl-10":"_X4Bq6","background-shine":"_361tW","path":"_qtb88","line":"_XQ9Yw","skeleton":"_BQ0X7","skeleton-animate":"_vEv3B","skeleton-dark":"_l5qsf","skeleton-dark-animate":"_yk159","skeleton-transparent":"_857E4","skeleton-transparent-animate":"_RzhIE","semi-transparent":"_LacS6","no-margins":"_bmB3S","dots":"_5kMd-","colored":"_-lTGD","small":"_GTU1q","extra-small":"_BEmi7","align-left":"_HuG6N","align-right":"_U3h5U"};
1158
1162
 
1159
1163
  /**
1160
1164
  * LoadingDots Component - Displays a loading animation with dots.
@@ -1194,7 +1198,7 @@ LoadingDots.propTypes = {
1194
1198
  /**
1195
1199
  * Button component - A versatile and customizable button for React applications.
1196
1200
  * It supports various sizes, styles, and functionalities, including loaders, icons, and handling of click events.
1197
- * This component can also be used as a link when integrated with `react-router-dom`.
1201
+ * This component can also be used as a link if "to" is provided.
1198
1202
  *
1199
1203
  * @component
1200
1204
  * @param {Object} props
@@ -1264,7 +1268,10 @@ const Button = ({
1264
1268
  setIsCheckShown(false);
1265
1269
  }, 2000);
1266
1270
  }
1267
- e.persist(); // Persisting React's SyntheticEvent to be able to use it in any async context
1271
+ if (e != null && e.persist) {
1272
+ // Persisting React's SyntheticEvent to be able to use it in any async context
1273
+ e.persist();
1274
+ }
1268
1275
  !_propagatePrimaryButtonClick && e.stopPropagation();
1269
1276
  if (_loader) {
1270
1277
  setIsLoading(true);
@@ -1277,11 +1284,11 @@ const Button = ({
1277
1284
  return /*#__PURE__*/React.createElement(React.Fragment, null, _isFormSubmittingButton ? /*#__PURE__*/React.createElement("input", {
1278
1285
  type: "submit",
1279
1286
  hidden: true
1280
- }) : null, _to ? /*#__PURE__*/React.createElement(Link, {
1287
+ }) : null, _to ? /*#__PURE__*/React.createElement("a", {
1281
1288
  className: classNames,
1282
1289
  onClick: e => _handleError(buttonClick, e),
1283
- to: _to,
1284
- innerRef: buttonRef
1290
+ href: _to,
1291
+ ref: buttonRef
1285
1292
  }, _icon ? /*#__PURE__*/React.createElement("div", {
1286
1293
  className: styles$1["button-with-icon"] + (_bigIcon ? ` ${styles$1["big-icon"]}` : "")
1287
1294
  }, /*#__PURE__*/React.createElement("img", {
@@ -1313,7 +1320,7 @@ const Button = ({
1313
1320
  Button.propTypes = {
1314
1321
  size: PropTypes.oneOf(["xl", "lg", "md", "sm"]),
1315
1322
  className: PropTypes.string,
1316
- mode: PropTypes.oneOf(["transparent", "white", "primary", "primary-bordered", "primary-transparent", "transparent-bordered", "transparent-without-shadow"]),
1323
+ mode: PropTypes.oneOf(["transparent", "white", "white-flat", "primary", "primary-bordered", "primary-transparent", "transparent-bordered", "transparent-without-shadow"]),
1317
1324
  onClick: PropTypes.func,
1318
1325
  loader: PropTypes.bool,
1319
1326
  loading: PropTypes.bool,
@@ -1353,5 +1360,3753 @@ Button.defaultProps = {
1353
1360
  handleError: func => func()
1354
1361
  };
1355
1362
 
1356
- export { Button, LoadingDots };
1363
+ const SupportChat = ({
1364
+ url,
1365
+ websiteToken,
1366
+ welcomeMessage: _welcomeMessage = "",
1367
+ locale: _locale = "en"
1368
+ }) => {
1369
+ useEffect(() => {
1370
+ window.chatwootSettings = {
1371
+ position: "right",
1372
+ type: "standard",
1373
+ launcherTitle: _welcomeMessage,
1374
+ locale: _locale
1375
+ };
1376
+ (function (d, t) {
1377
+ var BASE_URL = url;
1378
+ var g = d.createElement(t),
1379
+ s = d.getElementsByTagName(t)[0];
1380
+ g.src = BASE_URL + "/packs/js/sdk.js";
1381
+ g.defer = true;
1382
+ g.async = true;
1383
+ s.parentNode.insertBefore(g, s);
1384
+ g.onload = function () {
1385
+ window.chatwootSDK.run({
1386
+ websiteToken: websiteToken,
1387
+ baseUrl: BASE_URL
1388
+ });
1389
+ };
1390
+ })(document, "script");
1391
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1392
+ }, []);
1393
+ return null;
1394
+ };
1395
+ SupportChat.propTypes = {
1396
+ url: PropTypes.string.isRequired,
1397
+ websiteToken: PropTypes.string.isRequired,
1398
+ welcomeMessage: PropTypes.string,
1399
+ locale: PropTypes.string
1400
+ };
1401
+ SupportChat.defaultProps = {
1402
+ welcomeMessage: "",
1403
+ locale: "en"
1404
+ };
1405
+
1406
+ var s = {"container":"_DYS-g","m-0":"_85R9d","p-0":"_wi0-U","m-1":"_YoewO","p-1":"_vuJBW","m-2":"_ruaYI","p-2":"_dO-cg","m-3":"_3Oh59","p-3":"_x4uSr","m-4":"_zN8us","p-4":"_rjv4I","m-5":"_5T1F-","p-5":"_-nWHT","m-6":"_Skgdf","p-6":"_Oux4z","m-7":"_yKPSq","p-7":"_sOsqF","m-8":"_8EoDT","p-8":"_G4M7b","m-9":"_ZZJBC","p-9":"_2PU3N","m-10":"_XRmXO","p-10":"_lhLN8","ml-0":"_SIynD","pl-0":"_VCLgc","ml-1":"_9vhMT","pl-1":"_4O5ig","ml-2":"_f1saV","pl-2":"_sHxk9","ml-3":"_kiltH","pl-3":"_jUw5Z","ml-4":"_CF1wj","pl-4":"_eXCZ1","ml-5":"_HZlH9","pl-5":"_6xbwv","ml-6":"_jNpyz","pl-6":"_k5lHk","ml-7":"_LgB9F","pl-7":"_ol9Tb","ml-8":"_I25tR","pl-8":"_TN4dc","ml-9":"_ywWxC","pl-9":"_4UsSQ","ml-10":"_9rfct","pl-10":"_LoViP","mr-0":"_-1PzO","pr-0":"_Ekco3","mr-1":"_EfRd0","pr-1":"_GspC-","mr-2":"_91QSK","pr-2":"_dU7Vb","mr-3":"_tW92i","pr-3":"_qNnnG","mr-4":"_XC1FW","pr-4":"_09RVw","mr-5":"_I4KRh","pr-5":"_eag2b","mr-6":"_E-KDc","pr-6":"_0d7JN","mr-7":"_9GUd-","pr-7":"_5Jseh","mr-8":"_Z-z3u","pr-8":"_rjPRa","mr-9":"_R2d68","pr-9":"_YI-lc","mr-10":"_ORX-B","pr-10":"_F5ib8","mt-0":"_OAl4b","pt-0":"_iJ5QU","mt-1":"_x72-c","pt-1":"_DGuKS","mt-2":"_ZYCC4","pt-2":"_6oj3E","mt-3":"_ADXHX","pt-3":"_asJoO","mt-4":"_Bz8Hu","pt-4":"_N7CCb","mt-5":"_OyQQ8","pt-5":"_C46Cf","mt-6":"_Bfrcj","pt-6":"_NN4sF","mt-7":"_RWFV0","pt-7":"_zUauA","mt-8":"_v7txm","pt-8":"_qgvMl","mt-9":"_9s32w","pt-9":"_aJZt7","mt-10":"_feBhr","pt-10":"_EfI4E","mb-0":"_RUzt9","pb-0":"_0Zjn8","mb-1":"_EmcPj","pb-1":"_zuqTv","mb-2":"_jYcdG","pb-2":"_fjMa6","mb-3":"_Lcgzu","pb-3":"_MHHa3","mb-4":"_Aoo0-","pb-4":"_B1ap3","mb-5":"_xdjCc","pb-5":"_lnrC3","mb-6":"_TFmkS","pb-6":"_YNj2R","mb-7":"_i0-JZ","pb-7":"_qSvSL","mb-8":"_7ziqB","pb-8":"_W-Cdi","mb-9":"_lUUVq","pb-9":"_LrgoL","mb-10":"_xX8mu","pb-10":"_DU6C6","mx-0":"_71D1Q","px-0":"_U8dyv","mx-1":"_2VhDN","px-1":"_d8Tlo","mx-2":"_uDkn4","px-2":"_a6Z6h","mx-3":"_W9yqm","px-3":"_MCbca","mx-4":"_sIDVk","px-4":"_wZ8Qz","mx-5":"_-6tEi","px-5":"_8vfpL","mx-6":"_mbXa9","px-6":"_LcSh5","mx-7":"_mF9-c","px-7":"_TfjhQ","mx-8":"_RG7wu","px-8":"_19Sdb","mx-9":"_JkKgx","px-9":"_Ir3LH","mx-10":"_70tWA","px-10":"_d1BrW","my-0":"_0PauS","py-0":"_FP0FE","my-1":"_znn6s","py-1":"_-FHoU","my-2":"_EqZco","py-2":"_fuTfe","my-3":"_D2LQ5","py-3":"_YWhnK","my-4":"_kCXTL","py-4":"_j1vj6","my-5":"_naEoR","py-5":"_QK3Z-","my-6":"_L1TOy","py-6":"_dQH-e","my-7":"_sVZ3Y","py-7":"_Fi779","my-8":"_1mAkX","py-8":"_yTTVv","my-9":"_jCeMV","py-9":"_qfn2C","my-10":"_eqneu","py-10":"_Atu-j","m-sm-0":"_hsKWE","p-sm-0":"_j3m-2","m-sm-1":"_NQOee","p-sm-1":"_sB5mJ","m-sm-2":"_KivoH","p-sm-2":"_YjE2j","m-sm-3":"_kObhZ","p-sm-3":"_TDlKW","m-sm-4":"_aJWH3","p-sm-4":"_Vntgp","m-sm-5":"_k-Hjs","p-sm-5":"_mJt7k","m-sm-6":"_Yxxob","p-sm-6":"_E5a-A","m-sm-7":"_M1OJO","p-sm-7":"_-5OJr","m-sm-8":"_UYrWD","p-sm-8":"_FJeV6","m-sm-9":"_DosWW","p-sm-9":"_T9yES","m-sm-10":"_tLYqH","p-sm-10":"_5dbE7","ml-sm-0":"_PM9wP","pl-sm-0":"_0Eoi7","ml-sm-1":"_Mb-hF","pl-sm-1":"_n4rCF","ml-sm-2":"_JJgiX","pl-sm-2":"_WOdAR","ml-sm-3":"_umhPB","pl-sm-3":"_tETqx","ml-sm-4":"_PQ088","pl-sm-4":"_ON2pV","ml-sm-5":"_IrMTT","pl-sm-5":"_12IZU","ml-sm-6":"_s8vHJ","pl-sm-6":"_9Od-S","ml-sm-7":"_4uuhE","pl-sm-7":"_TTrnJ","ml-sm-8":"_6TEO5","pl-sm-8":"_ZEPSH","ml-sm-9":"_I05iS","pl-sm-9":"_F5rHi","ml-sm-10":"_AJZ2R","pl-sm-10":"_zgudu","mr-sm-0":"_AD7v0","pr-sm-0":"_katlS","mr-sm-1":"_RMNwS","pr-sm-1":"_SC0VS","mr-sm-2":"_YFbee","pr-sm-2":"_I2cqm","mr-sm-3":"_KJzfk","pr-sm-3":"_aDNge","mr-sm-4":"_ERg9u","pr-sm-4":"_wlgHy","mr-sm-5":"_spxY0","pr-sm-5":"_pAEEu","mr-sm-6":"_HM7Z6","pr-sm-6":"_rf9My","mr-sm-7":"_b-V6W","pr-sm-7":"_YFXWV","mr-sm-8":"_96NiE","pr-sm-8":"_0ynKz","mr-sm-9":"_9NqL0","pr-sm-9":"_ZEN2v","mr-sm-10":"_oxmC7","pr-sm-10":"_AsAlz","mt-sm-0":"_Yl8e7","pt-sm-0":"_fkSmd","mt-sm-1":"_l4X69","pt-sm-1":"_i7WdP","mt-sm-2":"_ggYWK","pt-sm-2":"_3-z2g","mt-sm-3":"_IzZ-y","pt-sm-3":"_c3PEq","mt-sm-4":"_BbTvo","pt-sm-4":"_iAXVy","mt-sm-5":"_RNscW","pt-sm-5":"_7dHkj","mt-sm-6":"_iKCRS","pt-sm-6":"_an673","mt-sm-7":"_1Atcr","pt-sm-7":"_KA-HC","mt-sm-8":"_45ifh","pt-sm-8":"_26wBi","mt-sm-9":"_VaqUk","pt-sm-9":"_cx10Q","mt-sm-10":"_83RI-","pt-sm-10":"_vTZq7","mb-sm-0":"_IDhal","pb-sm-0":"_3IjzN","mb-sm-1":"_sjxoK","pb-sm-1":"_fmWwG","mb-sm-2":"_GNlxw","pb-sm-2":"_r3zJV","mb-sm-3":"_FFWRt","pb-sm-3":"_arvvr","mb-sm-4":"_qaIKp","pb-sm-4":"_wSca9","mb-sm-5":"_-cXAZ","pb-sm-5":"_grIUD","mb-sm-6":"_PUPyR","pb-sm-6":"_nA8VL","mb-sm-7":"_t7JYD","pb-sm-7":"_OpbJn","mb-sm-8":"_x1wdN","pb-sm-8":"_3Z-mA","mb-sm-9":"_BPrSY","pb-sm-9":"_b-NQ7","mb-sm-10":"_lSN9Q","pb-sm-10":"_E7xwy","mx-sm-0":"_-cSXk","px-sm-0":"_VlISI","mx-sm-1":"_6derN","px-sm-1":"_in01f","mx-sm-2":"_nskhZ","px-sm-2":"_Thnqg","mx-sm-3":"_xR8rV","px-sm-3":"_zUOaf","mx-sm-4":"_0c-bw","px-sm-4":"_X-g0R","mx-sm-5":"_p3iVv","px-sm-5":"_RdgSR","mx-sm-6":"_vK8xL","px-sm-6":"_xGpLP","mx-sm-7":"_uvb2q","px-sm-7":"_YvDjG","mx-sm-8":"_8nvEy","px-sm-8":"_L3gRg","mx-sm-9":"_pRh4Y","px-sm-9":"_5yig0","mx-sm-10":"_syXdz","px-sm-10":"_TfV9e","my-sm-0":"_WXfoP","py-sm-0":"_SBx-N","my-sm-1":"_dPEq6","py-sm-1":"_UrxQl","my-sm-2":"_ULvTZ","py-sm-2":"_I4Sll","my-sm-3":"_YVvfW","py-sm-3":"_9qflx","my-sm-4":"_j4ltv","py-sm-4":"_u-NN2","my-sm-5":"_mC1LQ","py-sm-5":"_6Wcc2","my-sm-6":"_eE8rw","py-sm-6":"_AeFpW","my-sm-7":"_CAnzA","py-sm-7":"_7h-Vs","my-sm-8":"_Z9Aft","py-sm-8":"_Ww8LU","my-sm-9":"_3sbBd","py-sm-9":"_ZcdCh","my-sm-10":"_PGBDh","py-sm-10":"_i6Fc2","m-lg-0":"_PkOb8","p-lg-0":"_3UpkE","m-lg-1":"_nCbz9","p-lg-1":"_1lThO","m-lg-2":"_ARtYq","p-lg-2":"_vHeBX","m-lg-3":"_cpKBp","p-lg-3":"_n-7p1","m-lg-4":"_1bWgj","p-lg-4":"_niPSW","m-lg-5":"_T9s09","p-lg-5":"_OS1Yy","m-lg-6":"_GvZeA","p-lg-6":"_8cgsA","m-lg-7":"_d0oC7","p-lg-7":"_TuBYJ","m-lg-8":"_slAc2","p-lg-8":"_ay3FH","m-lg-9":"_r3-kR","p-lg-9":"_IuC-U","m-lg-10":"_9P6I9","p-lg-10":"_RUR7-","ml-lg-0":"_xf3wx","pl-lg-0":"_Q-8ZY","ml-lg-1":"_4tg9Q","pl-lg-1":"_2rsuI","ml-lg-2":"_-YU8G","pl-lg-2":"_Eds1N","ml-lg-3":"_tD4RQ","pl-lg-3":"_R0Rk2","ml-lg-4":"_pZcNJ","pl-lg-4":"_5jvIR","ml-lg-5":"_sjk-4","pl-lg-5":"_RwLHv","ml-lg-6":"_dyXyT","pl-lg-6":"_nVLAC","ml-lg-7":"_FPuf8","pl-lg-7":"_M5bYC","ml-lg-8":"_Uet9k","pl-lg-8":"_UrAQv","ml-lg-9":"_VPraG","pl-lg-9":"_8HJkV","ml-lg-10":"_ILHbQ","pl-lg-10":"_QaxaT","mr-lg-0":"_2QrJI","pr-lg-0":"_0XJPD","mr-lg-1":"_qSATY","pr-lg-1":"_fzyzB","mr-lg-2":"_pY4IE","pr-lg-2":"_lc7Gu","mr-lg-3":"_KeRuW","pr-lg-3":"_zc2cu","mr-lg-4":"_RvxVY","pr-lg-4":"_v5XDn","mr-lg-5":"_Kipoo","pr-lg-5":"_K-vHR","mr-lg-6":"_1nl-K","pr-lg-6":"_nVUH-","mr-lg-7":"_M1Ue1","pr-lg-7":"_B75ua","mr-lg-8":"_CmlKz","pr-lg-8":"_FnY12","mr-lg-9":"_8-uRA","pr-lg-9":"_1DG22","mr-lg-10":"_vzMQh","pr-lg-10":"_2iqul","mt-lg-0":"_1eCp-","pt-lg-0":"_ucRUw","mt-lg-1":"_9YQ4e","pt-lg-1":"_pzmV0","mt-lg-2":"_1Z7OF","pt-lg-2":"_FUFhX","mt-lg-3":"_HPI-W","pt-lg-3":"_NwVgV","mt-lg-4":"_duZYq","pt-lg-4":"_h0NfP","mt-lg-5":"_sszGU","pt-lg-5":"_nNi-i","mt-lg-6":"_YYWl4","pt-lg-6":"_rqDrl","mt-lg-7":"_MmkeY","pt-lg-7":"_TZx0T","mt-lg-8":"_mdoth","pt-lg-8":"_2pGPR","mt-lg-9":"_csumg","pt-lg-9":"_BIWSR","mt-lg-10":"_TN07y","pt-lg-10":"_ojQGh","mb-lg-0":"_eXETo","pb-lg-0":"_FeL5F","mb-lg-1":"_Zc1bw","pb-lg-1":"_34sNS","mb-lg-2":"_2XgD-","pb-lg-2":"_OTB4o","mb-lg-3":"_xJ4EC","pb-lg-3":"_-Uc7P","mb-lg-4":"_thqbO","pb-lg-4":"_lqHuw","mb-lg-5":"_gDmAe","pb-lg-5":"_zAiLu","mb-lg-6":"_96HP2","pb-lg-6":"_TCehU","mb-lg-7":"_1Guas","pb-lg-7":"_vn7-Z","mb-lg-8":"_Cc-m8","pb-lg-8":"_dbCuX","mb-lg-9":"_U5Qon","pb-lg-9":"_b54cM","mb-lg-10":"_cGYyA","pb-lg-10":"_U5qus","mx-lg-0":"_TDPp0","px-lg-0":"_hUlWn","mx-lg-1":"_uh5DO","px-lg-1":"_N8r0e","mx-lg-2":"_vsfWJ","px-lg-2":"_LaBP6","mx-lg-3":"_JxquV","px-lg-3":"_Tb8mk","mx-lg-4":"_wDKd1","px-lg-4":"_lIguL","mx-lg-5":"_RSd-x","px-lg-5":"_Mdf1f","mx-lg-6":"_uvK2D","px-lg-6":"_4k20p","mx-lg-7":"_iXTh7","px-lg-7":"_W2faz","mx-lg-8":"_HHM9t","px-lg-8":"_n54Rq","mx-lg-9":"_douwI","px-lg-9":"_KWSHJ","mx-lg-10":"_L-r4v","px-lg-10":"_qeSLU","my-lg-0":"_U9qcF","py-lg-0":"_sSD4U","my-lg-1":"_vNl2c","py-lg-1":"_Cfkag","my-lg-2":"_gVDuB","py-lg-2":"_FwQsB","my-lg-3":"_oiJaa","py-lg-3":"_FASGS","my-lg-4":"_va2Tm","py-lg-4":"_EPTkJ","my-lg-5":"_jvYOP","py-lg-5":"_NTxiG","my-lg-6":"_8Y7Xj","py-lg-6":"_Nrsd7","my-lg-7":"_-e9e5","py-lg-7":"_NOh2l","my-lg-8":"_nyCDl","py-lg-8":"_fpL5p","my-lg-9":"_BbcqH","py-lg-9":"_VlI3L","my-lg-10":"_OGNmd","py-lg-10":"_Q-3bw","m-md-0":"_P6WIc","p-md-0":"_3YuAI","m-md-1":"_VwK3z","p-md-1":"_ArFsR","m-md-2":"_5Hp7o","p-md-2":"_-R4rJ","m-md-3":"_J55VC","p-md-3":"_TxlAj","m-md-4":"_FHPQG","p-md-4":"_iZW10","m-md-5":"_Kiuiv","p-md-5":"_0Qiry","m-md-6":"_Ja9dp","p-md-6":"_GBAS-","m-md-7":"_uuE4u","p-md-7":"_kAuu-","m-md-8":"_CaU4W","p-md-8":"_GbyMJ","m-md-9":"_brWmN","p-md-9":"_-1z0O","m-md-10":"_dIML4","p-md-10":"_eJliD","ml-md-0":"_nuVMQ","pl-md-0":"_PCyiw","ml-md-1":"_NX2qp","pl-md-1":"_yJ39l","ml-md-2":"_BV1WB","pl-md-2":"_x24YX","ml-md-3":"_kvTBw","pl-md-3":"_7G7wo","ml-md-4":"_s1oaO","pl-md-4":"_nTHBq","ml-md-5":"_2AyzN","pl-md-5":"_VmocP","ml-md-6":"_QEhdf","pl-md-6":"_Ywy9t","ml-md-7":"_Mybnc","pl-md-7":"_zHudI","ml-md-8":"_AT4F-","pl-md-8":"_1-CLq","ml-md-9":"_cZ0UL","pl-md-9":"_AKT8q","ml-md-10":"_uo54H","pl-md-10":"_2Edrz","mr-md-0":"_8NtcB","pr-md-0":"_BN5kR","mr-md-1":"_hIIXR","pr-md-1":"_KWi0C","mr-md-2":"_kP9GD","pr-md-2":"_fo1s0","mr-md-3":"_ptgO9","pr-md-3":"_AIGLm","mr-md-4":"_GJNi6","pr-md-4":"_-ZfQA","mr-md-5":"_hW-OG","pr-md-5":"_ePqmc","mr-md-6":"_ghuDl","pr-md-6":"_C9rlZ","mr-md-7":"_bIHB6","pr-md-7":"_xPHzJ","mr-md-8":"_6ZssD","pr-md-8":"_-N-QR","mr-md-9":"_T-XzG","pr-md-9":"_k8hdA","mr-md-10":"_26xvU","pr-md-10":"_U6Fpn","mt-md-0":"_ZIFgT","pt-md-0":"_6JBhp","mt-md-1":"_lIu84","pt-md-1":"_yPyiK","mt-md-2":"_sWcbm","pt-md-2":"_-7S2K","mt-md-3":"_-Zt6X","pt-md-3":"_pmFds","mt-md-4":"_dlz9t","pt-md-4":"_HQv-M","mt-md-5":"_9tUBj","pt-md-5":"_Jdc38","mt-md-6":"_BEZDD","pt-md-6":"_c3r6r","mt-md-7":"_KSCEr","pt-md-7":"_-Tpjo","mt-md-8":"_O-cOs","pt-md-8":"_DPwEz","mt-md-9":"_eBVAf","pt-md-9":"_Fnftl","mt-md-10":"_tlAu5","pt-md-10":"_ufMho","mb-md-0":"_NKFtN","pb-md-0":"_QEyOV","mb-md-1":"_t8EVs","pb-md-1":"_hVqy6","mb-md-2":"_Dwa5p","pb-md-2":"_A6iqX","mb-md-3":"_DAzrF","pb-md-3":"_o9L2-","mb-md-4":"_zMG5y","pb-md-4":"_wC2az","mb-md-5":"_LYF0o","pb-md-5":"_rrbij","mb-md-6":"_tUQcN","pb-md-6":"_MgAD-","mb-md-7":"_9lVsl","pb-md-7":"_Z7z8R","mb-md-8":"_CMrj4","pb-md-8":"_X4Qb0","mb-md-9":"_dQuWg","pb-md-9":"_98aa5","mb-md-10":"_tjfzH","pb-md-10":"_n5Id2","mx-md-0":"_kbQ3E","px-md-0":"_LWqO4","mx-md-1":"_8dqNC","px-md-1":"_QBFBY","mx-md-2":"_QXy6I","px-md-2":"_vBqGQ","mx-md-3":"_asgRe","px-md-3":"_i67O7","mx-md-4":"_-9eXp","px-md-4":"_ZQIEY","mx-md-5":"_l4FN1","px-md-5":"_vYBmq","mx-md-6":"_j4Fiy","px-md-6":"_BLvHs","mx-md-7":"_hg5ZA","px-md-7":"_OclOz","mx-md-8":"_NNMXz","px-md-8":"_KUBjL","mx-md-9":"_x5vxD","px-md-9":"_x1Hj-","mx-md-10":"_RnJFW","px-md-10":"_laoTv","my-md-0":"_gAG5i","py-md-0":"_KQkB8","my-md-1":"_90Emt","py-md-1":"_a93vq","my-md-2":"_wzerE","py-md-2":"_vpawj","my-md-3":"_ijUtT","py-md-3":"_9G-7C","my-md-4":"_GfQTx","py-md-4":"_vGRDM","my-md-5":"_MVaN3","py-md-5":"_5Ju4e","my-md-6":"_StvD2","py-md-6":"_03iO9","my-md-7":"_nlUi8","py-md-7":"_e58lN","my-md-8":"_VKoKR","py-md-8":"_Xa5lD","my-md-9":"_nLjef","py-md-9":"_88ryZ","my-md-10":"_-f4Oc","py-md-10":"_60CJ8","m-xl-0":"_YdUVc","p-xl-0":"_ceNl-","m-xl-1":"_cn-PK","p-xl-1":"_8pBVr","m-xl-2":"_UNu8h","p-xl-2":"_6mIBX","m-xl-3":"_LXA70","p-xl-3":"_nkNjg","m-xl-4":"_DH3uC","p-xl-4":"_b631X","m-xl-5":"_PU5TK","p-xl-5":"_Y9Pj5","m-xl-6":"_DQUfX","p-xl-6":"_cmXs1","m-xl-7":"_Hr4dN","p-xl-7":"_pwyLG","m-xl-8":"_XkBIo","p-xl-8":"_oSfQ1","m-xl-9":"_TXGD8","p-xl-9":"_r8XiA","m-xl-10":"_cbucW","p-xl-10":"_FnUT2","ml-xl-0":"_Lc2b0","pl-xl-0":"_8ofmI","ml-xl-1":"_yOkOl","pl-xl-1":"_5cZix","ml-xl-2":"_F0JQw","pl-xl-2":"_pWIp6","ml-xl-3":"_9CDHy","pl-xl-3":"_M9MOq","ml-xl-4":"_L6LLW","pl-xl-4":"_NZlEo","ml-xl-5":"_Milvj","pl-xl-5":"_N-hPa","ml-xl-6":"_HEU-c","pl-xl-6":"_x-uz3","ml-xl-7":"_xVYoD","pl-xl-7":"_TV3yu","ml-xl-8":"_WVmm8","pl-xl-8":"_Wsfh3","ml-xl-9":"_Rse0C","pl-xl-9":"_p-0My","ml-xl-10":"_LN1Pv","pl-xl-10":"_WtXyv","mr-xl-0":"_aQ8fC","pr-xl-0":"_x7HY1","mr-xl-1":"_rzUKT","pr-xl-1":"_ggRzA","mr-xl-2":"_j88Jb","pr-xl-2":"_6Ztzi","mr-xl-3":"_RNldP","pr-xl-3":"_uC4PP","mr-xl-4":"_14KPU","pr-xl-4":"_RoGxi","mr-xl-5":"_MYSFB","pr-xl-5":"_0fjNm","mr-xl-6":"_aK553","pr-xl-6":"_B-5Vf","mr-xl-7":"_nLta-","pr-xl-7":"_AhsZ-","mr-xl-8":"_emyPo","pr-xl-8":"_Dc6lK","mr-xl-9":"_MqsWc","pr-xl-9":"_j4A-H","mr-xl-10":"_v7rIi","pr-xl-10":"_aIhOc","mt-xl-0":"_1KMHA","pt-xl-0":"_SmBQC","mt-xl-1":"_FpHTe","pt-xl-1":"_tRIkV","mt-xl-2":"_ISAHh","pt-xl-2":"_KcOk8","mt-xl-3":"_cklRo","pt-xl-3":"_MqQSr","mt-xl-4":"_iaWfp","pt-xl-4":"_mcXBl","mt-xl-5":"_qNaL5","pt-xl-5":"_3tRQZ","mt-xl-6":"_MjyPP","pt-xl-6":"_wGTYM","mt-xl-7":"_WkpWd","pt-xl-7":"_-fXMT","mt-xl-8":"_xgRm6","pt-xl-8":"_mNE0F","mt-xl-9":"_tHRgU","pt-xl-9":"_pUanr","mt-xl-10":"_75l23","pt-xl-10":"_VjjB-","mb-xl-0":"_wNZHn","pb-xl-0":"_6weX6","mb-xl-1":"_xbDsG","pb-xl-1":"_WLHB6","mb-xl-2":"_JCck5","pb-xl-2":"_Ef822","mb-xl-3":"_-Izvj","pb-xl-3":"_kizTx","mb-xl-4":"_wDLLt","pb-xl-4":"_6vfXW","mb-xl-5":"_qa8hX","pb-xl-5":"_2cdIL","mb-xl-6":"_PPuX7","pb-xl-6":"_SYsiu","mb-xl-7":"_au29R","pb-xl-7":"_Wo-v3","mb-xl-8":"_7DCh1","pb-xl-8":"_8Qtxz","mb-xl-9":"_U5ePL","pb-xl-9":"_QdSRg","mb-xl-10":"_xwDK-","pb-xl-10":"_5HXQF","mx-xl-0":"_U-5An","px-xl-0":"_t0GQI","mx-xl-1":"_l2Q9y","px-xl-1":"_-6SLy","mx-xl-2":"_OO5ra","px-xl-2":"_DpWnU","mx-xl-3":"_umWwt","px-xl-3":"_gLeFm","mx-xl-4":"_O6nxp","px-xl-4":"_RXch7","mx-xl-5":"_GLCbl","px-xl-5":"_wOP1U","mx-xl-6":"_n1gJF","px-xl-6":"_jHA8-","mx-xl-7":"_ZG5zQ","px-xl-7":"_33-Bi","mx-xl-8":"_wGBwu","px-xl-8":"_jnqCE","mx-xl-9":"_-q541","px-xl-9":"_hQqb-","mx-xl-10":"_oOjVu","px-xl-10":"_8iBI4","my-xl-0":"_5V5-G","py-xl-0":"_ZIETe","my-xl-1":"_VhBbg","py-xl-1":"_qkd1g","my-xl-2":"_MONRd","py-xl-2":"_wBVYq","my-xl-3":"_oUD7x","py-xl-3":"_9C1YA","my-xl-4":"_akz7W","py-xl-4":"_sczsh","my-xl-5":"_CEcRg","py-xl-5":"_xFnw3","my-xl-6":"_RReJQ","py-xl-6":"_gx-E-","my-xl-7":"_NTw09","py-xl-7":"_VniPR","my-xl-8":"_zhVnN","py-xl-8":"_e-lj8","my-xl-9":"_p5Z-c","py-xl-9":"_L1zCc","my-xl-10":"_NqJ-Z","py-xl-10":"_LGmu1","background-shine":"_HkIXJ","path":"_VW1Ys","line":"_x1Ry-","skeleton":"_rh5J1","skeleton-animate":"_ukRhW","skeleton-dark":"_SuY0j","skeleton-dark-animate":"_wHz7j","skeleton-transparent":"_DehL2","skeleton-transparent-animate":"_nwZzB","semi-transparent":"_KJuSy","asset-icon":"_V0pcT","small":"_AXy-6","asset-icon-primary":"_wDjNx","asset-icon-secondary":"_uTjfo"};
1407
+
1408
+ const AssetIcon = ({
1409
+ assetIconSrc,
1410
+ assetIconProtocolSrc: _assetIconProtocolSrc = null,
1411
+ fallbackSrc: _fallbackSrc = null,
1412
+ small: _small = false
1413
+ }) => {
1414
+ const handleFailedLoad = e => {
1415
+ e.target.onerror = null;
1416
+ e.target.src = _fallbackSrc;
1417
+ };
1418
+ return /*#__PURE__*/React.createElement("div", {
1419
+ className: s["asset-icon"] + (_small ? " " + s["small"] : "")
1420
+ }, /*#__PURE__*/React.createElement("img", {
1421
+ src: assetIconSrc,
1422
+ className: s["asset-icon-primary"] + (_small ? " " + s["small"] : ""),
1423
+ alt: " ",
1424
+ onError: handleFailedLoad
1425
+ }), _assetIconProtocolSrc ? /*#__PURE__*/React.createElement("img", {
1426
+ src: _assetIconProtocolSrc,
1427
+ className: s["asset-icon-secondary"] + (_small ? " " + s["small"] : ""),
1428
+ alt: " ",
1429
+ onError: handleFailedLoad
1430
+ }) : "");
1431
+ };
1432
+ AssetIcon.propTypes = {
1433
+ assetIconSrc: PropTypes.string.isRequired,
1434
+ assetIconProtocolSrc: PropTypes.string,
1435
+ fallbackSrc: PropTypes.string,
1436
+ small: PropTypes.bool
1437
+ };
1438
+ AssetIcon.defaultProps = {
1439
+ assetIconProtocolSrc: null,
1440
+ fallbackSrc: null,
1441
+ small: false
1442
+ };
1443
+
1444
+ class LogsStorage {
1445
+ static saveLog(log) {
1446
+ this._inMemoryStorage.push(log);
1447
+ }
1448
+ static getInMemoryLogs() {
1449
+ return this._inMemoryStorage;
1450
+ }
1451
+ static getAllLogs() {
1452
+ let storedLogs = "";
1453
+ if (typeof window !== "undefined") {
1454
+ storedLogs = localStorage.getItem(this._logsStorageId);
1455
+ }
1456
+ return `${storedLogs}\n${this._inMemoryStorage.join("\n")}`;
1457
+ }
1458
+
1459
+ /**
1460
+ * @param logger {Logger}
1461
+ */
1462
+ static saveToTheDisk(logger) {
1463
+ try {
1464
+ const MAX_LOCAL_STORAGE_VOLUME_BYTES = 5 * 1024 * 1024;
1465
+ const MAX_LOGS_STORAGE_BYTES = MAX_LOCAL_STORAGE_VOLUME_BYTES * 0.65;
1466
+ if (typeof window !== "undefined") {
1467
+ const existingLogs = localStorage.getItem(this._logsStorageId);
1468
+ const logsString = `${existingLogs}\n${this._inMemoryStorage.join("\n")}`;
1469
+ const lettersCountToRemove = logsString.length - Math.round(MAX_LOGS_STORAGE_BYTES / 2);
1470
+ if (lettersCountToRemove > 0) {
1471
+ localStorage.setItem(this._logsStorageId, logsString.slice(lettersCountToRemove, logsString.length));
1472
+ } else {
1473
+ localStorage.setItem(this._logsStorageId, logsString);
1474
+ }
1475
+ this._inMemoryStorage = [];
1476
+ }
1477
+ } catch (e) {
1478
+ logger == null || logger.logError(e, "saveToTheDisk", "Failed to save logs to disk");
1479
+ }
1480
+ }
1481
+ static removeAllClientLogs() {
1482
+ if (typeof window !== "undefined") {
1483
+ if (localStorage.getItem("doNotRemoveClientLogsWhenSignedOut") !== "true") {
1484
+ localStorage.removeItem(this._logsStorageId);
1485
+ }
1486
+ }
1487
+ this._inMemoryStorage = [];
1488
+ }
1489
+ static setDoNotRemoveClientLogsWhenSignedOut(value) {
1490
+ if (typeof window !== "undefined") {
1491
+ localStorage.setItem("doNotRemoveClientLogsWhenSignedOut", value);
1492
+ }
1493
+ }
1494
+ }
1495
+ LogsStorage._inMemoryStorage = [];
1496
+ LogsStorage._logsStorageId = "clietnLogs_j203fj2D0n-d1";
1497
+
1498
+ /**
1499
+ * Stringify given object by use of JSON.stringify but handles circular structures and "response", "request" properties
1500
+ * to avoid stringing redundant data when printing errors containing request/response objects.
1501
+ *
1502
+ * @param object - object to be stringed
1503
+ * @param indent - custom indentation
1504
+ * @return {string} - stringed object
1505
+ */
1506
+ function safeStringify(object, indent = 2) {
1507
+ let cache = [];
1508
+ if (typeof object === "string" || typeof object === "function" || typeof object === "number" || typeof object === "undefined" || typeof object === "boolean") {
1509
+ return String(object);
1510
+ }
1511
+ const retVal = JSON.stringify(object, (key, value) => {
1512
+ if (key.toLowerCase().includes("request")) {
1513
+ return JSON.stringify({
1514
+ body: value == null ? void 0 : value.body,
1515
+ query: value == null ? void 0 : value.query,
1516
+ headers: value == null ? void 0 : value.headers
1517
+ });
1518
+ }
1519
+ if (key.toLowerCase().includes("response")) {
1520
+ return JSON.stringify({
1521
+ statusText: value == null ? void 0 : value.statusText,
1522
+ status: value == null ? void 0 : value.status,
1523
+ data: value == null ? void 0 : value.data,
1524
+ headers: value == null ? void 0 : value.headers
1525
+ });
1526
+ }
1527
+ return typeof value === "object" && value !== null ? cache.includes(value) ? "duplicated reference" // Duplicated references were found, discarding this key
1528
+ : cache.push(value) && value // Store value in our collection
1529
+ : value;
1530
+ }, indent);
1531
+ cache = null;
1532
+ return retVal;
1533
+ }
1534
+
1535
+ class Logger {
1536
+ /**
1537
+ * Logs to client logs storage.
1538
+ *
1539
+ * WARNING! this method should ce used carefully for critical logging as we have the restriction for storing logs
1540
+ * on client side as we store them inside the local storage. Please see details inside storage.js
1541
+ * @param logString {string} log string
1542
+ * @param source {string} source of the log entry
1543
+ */
1544
+ static log(logString, source) {
1545
+ const timestamp = new Date().toISOString();
1546
+ LogsStorage.saveLog(`${timestamp}|${source}:${logString}`);
1547
+ }
1548
+ static logError(e, settingFunction, additionalMessage = "", onlyToConsole = false) {
1549
+ var _e$errorDescription, _e$howToFix;
1550
+ let message = `\nFunction call ${settingFunction != null ? settingFunction : ""} failed. Error message: ${e == null ? void 0 : e.message}. ${additionalMessage} `;
1551
+ message += `${(_e$errorDescription = e == null ? void 0 : e.errorDescription) != null ? _e$errorDescription : ""}${(_e$howToFix = e == null ? void 0 : e.howToFix) != null ? _e$howToFix : ""}` + ((e == null ? void 0 : e.httpStatus) === 403 ? "Authentication has expired or was lost. " : "");
1552
+ if (e != null && e.response) {
1553
+ try {
1554
+ const responseData = safeStringify({
1555
+ response: e.response
1556
+ });
1557
+ responseData && (message += `\n${responseData}. `);
1558
+ } catch (e) {}
1559
+ }
1560
+ const finalErrorText = message + ". " + safeStringify(e);
1561
+ // eslint-disable-next-line no-console
1562
+ console.error(finalErrorText, e);
1563
+ if (!onlyToConsole) {
1564
+ this.log(finalErrorText, "logError");
1565
+ }
1566
+ }
1567
+ }
1568
+
1569
+ function useCallHandlingErrors() {
1570
+ const [, setState] = useState();
1571
+ return useCallback(async (functionToBeCalled, event) => {
1572
+ try {
1573
+ await functionToBeCalled(event);
1574
+ } catch (error) {
1575
+ Logger.logError(error, (functionToBeCalled == null ? void 0 : functionToBeCalled.name) || "errorBoundaryTrigger", "Caught by ErrorBoundary");
1576
+ // Triggering ErrorBoundary
1577
+ setState(() => {
1578
+ throw error;
1579
+ });
1580
+ }
1581
+ }, []);
1582
+ }
1583
+
1584
+ /**
1585
+ * Adds reference to standard state variable. It is helpful to be able to use state variable value inside
1586
+ * event handlers and other callbacks without the need to call setState(prev => { value = prev; return prev; }).
1587
+ *
1588
+ * @param initialValue {any} to be passed to useState
1589
+ * @return {[React.Ref, function]} reference to state variable and its setter
1590
+ */
1591
+ function useReferredState(initialValue) {
1592
+ const [state, setState] = React.useState(initialValue);
1593
+ const reference = React.useRef(state);
1594
+ const setReferredState = value => {
1595
+ if (value && {}.toString.call(value) === "[object Function]") {
1596
+ value = value(reference.current);
1597
+ }
1598
+ reference.current = value;
1599
+ setState(value);
1600
+ };
1601
+ return [reference, setReferredState];
1602
+ }
1603
+
1604
+ const handleClickOutside = (exceptionsRefs, callback) => {
1605
+ function handleClick(event) {
1606
+ const isExceptionClicked = exceptionsRefs.find(ref => (ref == null ? void 0 : ref.current) && ref.current.contains(event.target));
1607
+ if (!isExceptionClicked) {
1608
+ callback();
1609
+ }
1610
+ }
1611
+ document.addEventListener("click", handleClick);
1612
+ return () => document.removeEventListener("click", handleClick);
1613
+ };
1614
+
1615
+ const PARAMETER_VALUES_SEPARATOR = "|*|"; // Sting that with high probability will not be in the user's data
1616
+
1617
+ /**
1618
+ * Adds specified parameter with values to the URL query string
1619
+ *
1620
+ * @param parameterName - String - name of the parameter
1621
+ * @param values - Array of String values
1622
+ * @param updateURLCallback - callback that will be called with the updated query string. Can be used to save it to URL
1623
+ */
1624
+ function saveQueryParameterAndValues(parameterName, values, updateURLCallback = newQueryString => {}) {
1625
+ let parametersAndValues = parseSearchString();
1626
+ parametersAndValues = parametersAndValues.filter(parameterAndValues => parameterAndValues[0] !== parameterName);
1627
+ const parameterValuesForURL = encodeURIComponent(values.join(PARAMETER_VALUES_SEPARATOR));
1628
+ parametersAndValues.push([parameterName, parameterValuesForURL]);
1629
+ const newQueryString = `?${parametersAndValues.map(parameterAndValues => parameterAndValues.join("=")).join("&")}`;
1630
+ updateURLCallback(newQueryString);
1631
+ return newQueryString;
1632
+ }
1633
+
1634
+ /**
1635
+ * Removes specified parameter with values from the URL query string
1636
+ *
1637
+ * @param parameterName - String - name of the parameter
1638
+ * @param updateURLCallback - callback that will be called with the updated query string. Can be used to save it to URL
1639
+ */
1640
+ // TODO: [tests, moderate] units required the same as or other functions in this module
1641
+ function removeQueryParameterAndValues(parameterName, updateURLCallback = newQueryString => {}) {
1642
+ let parametersAndValues = parseSearchString();
1643
+ parametersAndValues = parametersAndValues.filter(parameterAndValues => parameterAndValues[0] !== parameterName);
1644
+ const newQueryString = `?${parametersAndValues.map(parameterAndValues => parameterAndValues.join("=")).join("&")}`;
1645
+ updateURLCallback(newQueryString);
1646
+ return newQueryString;
1647
+ }
1648
+
1649
+ /**
1650
+ * Retrieves parameter values from the URL query string.
1651
+ *
1652
+ * If there are several parameters with the same name in the URL then all their values are returned
1653
+ *
1654
+ * @param name {string} - parameter name
1655
+ * @return {string[]} [] - if the parameter is not present in URL. [""] - if parameter present but has empty value
1656
+ */
1657
+ function getQueryParameterValues(name) {
1658
+ return parseSearchString().filter(parameterAndValue => parameterAndValue[0] === name).reduce((allValues, parameterAndValue) => {
1659
+ const values = decodeURIComponent(parameterAndValue[1] || "").split(PARAMETER_VALUES_SEPARATOR);
1660
+ return [...allValues, ...values];
1661
+ }, []);
1662
+ }
1663
+ function parseSearchString() {
1664
+ var _window$location$sear;
1665
+ const trimmed = (((_window$location$sear = window.location.search) == null ? void 0 : _window$location$sear.slice(1)) || "").trim();
1666
+ return trimmed && trimmed.split("&").map(parameterAndValue => parameterAndValue.split("=")) || [];
1667
+ }
1668
+ function getQueryParameterSingleValue(name) {
1669
+ return (getQueryParameterValues(name) || [])[0];
1670
+ }
1671
+
1672
+ /**
1673
+ * This function improves the passed error object (its message) by adding the passed function name
1674
+ * and additional message to it.
1675
+ * This is useful as Javascript doesn't guarantee the stack-traces, so we should manually add these details to errors
1676
+ * to be able to troubleshoot.
1677
+ *
1678
+ * @param e {Error}
1679
+ * @param settingFunction {string}
1680
+ * @param [additionalMessage=""] {string|undefined}
1681
+ * @throws {Error} always rethrows the original passed error but with an improved message
1682
+ */
1683
+ function improveAndRethrow(e, settingFunction, additionalMessage = "") {
1684
+ const message = improvedErrorMessage(e, settingFunction, additionalMessage);
1685
+ if (e) {
1686
+ e.message = message;
1687
+ throw e; // to preserve existing stacktrace if present
1688
+ }
1689
+ throw new Error(message);
1690
+ }
1691
+ function improvedErrorMessage(e, settingFunction, additionalMessage) {
1692
+ let message = `\nFunction call ${settingFunction != null ? settingFunction : ""} failed. `;
1693
+ e && e.message && (message += `Error message: ${e.message}. `);
1694
+ additionalMessage && (message += `${additionalMessage} `);
1695
+ return message;
1696
+ }
1697
+ function logErrorOrOutputToConsole(e) {
1698
+ try {
1699
+ // TODO: [dev] remove this after few weeks of testing output in real life
1700
+ // eslint-disable-next-line no-console
1701
+ console.log("BEFORE SAFE", e);
1702
+ Logger.log("logErrorOrOutputToConsole", safeStringify(e));
1703
+ } catch (e) {
1704
+ // eslint-disable-next-line no-console
1705
+ console.log("logErrorOrOutputToConsole", e);
1706
+ }
1707
+ }
1708
+
1709
+ class FiatCurrenciesService {
1710
+ static getFullCurrencyNameByCode(code = "") {
1711
+ const data = fiatCurrenciesList.find(currencyData => currencyData[0] === code.toUpperCase());
1712
+ return data && data[2] || null;
1713
+ }
1714
+ static isCodeValid(code) {
1715
+ return !!fiatCurrenciesList.find(currenciesData => currenciesData[0] === code);
1716
+ }
1717
+
1718
+ /**
1719
+ * Returns currency symbol by code if present
1720
+ *
1721
+ * @param code {string} currency code
1722
+ * @return {string|null} code or null if there is no symbol for the currency
1723
+ */
1724
+ static getCurrencySymbolByCode(code = "") {
1725
+ var _data$;
1726
+ const data = fiatCurrenciesList.find(currencyData => currencyData[0] === code.toUpperCase());
1727
+ return (_data$ = data == null ? void 0 : data[1]) != null ? _data$ : null;
1728
+ }
1729
+
1730
+ /**
1731
+ * @param code {string}
1732
+ * @return {number|null}
1733
+ */
1734
+ static getCurrencyDecimalCountByCode(code = "") {
1735
+ var _data$2;
1736
+ const data = fiatCurrenciesList.find(currencyData => currencyData[0] === code.toUpperCase());
1737
+ return (_data$2 = data == null ? void 0 : data[3]) != null ? _data$2 : null;
1738
+ }
1739
+ }
1740
+ const fiatCurrenciesList = [["USD", "$", "US Dollar", 2], ["CAD", "CA$", "Canadian Dollar", 2], ["EUR", "€", "Euro", 2], ["AED", "AED", "UAE Dirham", 2], ["AFN", "؋", "Afghan Afghani", 0], ["ALL", "ALL", "Albanian Lek", 0], ["AMD", "֏", "Armenian Dram", 0], ["ARS", "AR$", "Argentine Peso", 2], ["AUD", "AU$", "Australian Dollar", 2], ["AZN", "₼", "Azerbaijani Manat", 2], ["BAM", "KM", "Bosnia-Herzegovina Convertible Mark", 2], ["BDT", "Tk", "Bangladeshi Taka", 2], ["BGN", "BGN", "Bulgarian Lev", 2], ["BHD", "BD", "Bahraini Dinar", 3], ["BIF", "FBu", "Burundian Franc", 0], ["BND", "BN$", "Brunei Dollar", 2], ["BOB", "Bs", "Bolivian Boliviano", 2], ["BRL", "R$", "Brazilian Real", 2], ["BWP", "BWP", "Botswanan Pula", 2], ["BYN", "Br", "Belarusian Ruble", 2], ["BZD", "BZ$", "Belize Dollar", 2], ["CDF", "CDF", "Congolese Franc", 2], ["CHF", "CHF", "Swiss Franc", 2], ["CLP", "CL$", "Chilean Peso", 0], ["CNY", "CN¥", "Chinese Yuan", 2], ["COP", "CO$", "Colombian Peso", 0], ["CRC", "₡", "Costa Rican Colón", 0], ["CVE", "CV$", "Cape Verdean Escudo", 2], ["CZK", "Kč", "Czech Republic Koruna", 2], ["DJF", "Fdj", "Djiboutian Franc", 0], ["DKK", "Dkr", "Danish Krone", 2], ["DOP", "RD$", "Dominican Peso", 2], ["DZD", "DA", "Algerian Dinar", 2], ["EEK", "Ekr", "Estonian Kroon", 2], ["EGP", "EGP", "Egyptian Pound", 2], ["ERN", "Nfk", "Eritrean Nakfa", 2], ["ETB", "Br", "Ethiopian Birr", 2], ["GBP", "£", "British Pound Sterling", 2], ["GEL", "₾", "Georgian Lari", 2], ["GHS", "₵", "Ghanaian Cedi", 2], ["GNF", "FG", "Guinean Franc", 0], ["GTQ", "GTQ", "Guatemalan Quetzal", 2], ["HKD", "HK$", "Hong Kong Dollar", 2], ["HNL", "HNL", "Honduran Lempira", 2], ["HRK", "kn", "Croatian Kuna", 2], ["HUF", "Ft", "Hungarian Forint", 0], ["IDR", "Rp", "Indonesian Rupiah", 0], ["ILS", "₪", "Israeli New Sheqel", 2], ["INR", "₹", "Indian Rupee", 2], ["IQD", "IQD", "Iraqi Dinar", 0], ["IRR", "﷼", "Iranian Rial", 0], ["ISK", "Ikr", "Icelandic Króna", 0], ["JMD", "J$", "Jamaican Dollar", 2], ["JOD", "JD", "Jordanian Dinar", 3], ["JPY", "¥", "Japanese Yen", 0], ["KES", "Ksh", "Kenyan Shilling", 2], ["KHR", "KHR", "Cambodian Riel", 2], ["KMF", "CF", "Comorian Franc", 0], ["KRW", "₩", "South Korean Won", 0], ["KWD", "KD", "Kuwaiti Dinar", 3], ["KZT", "₸", "Kazakhstani Tenge", 2], ["LBP", "LB£", "Lebanese Pound", 0], ["LKR", "SLRs", "Sri Lankan Rupee", 2], ["LTL", "Lt", "Lithuanian Litas", 2], ["LVL", "Ls", "Latvian Lats", 2], ["LYD", "LD", "Libyan Dinar", 3], ["MAD", "MAD", "Moroccan Dirham", 2], ["MDL", "MDL", "Moldovan Leu", 2], ["MGA", "MGA", "Malagasy Ariary", 0], ["MKD", "MKD", "Macedonian Denar", 2], ["MMK", "MMK", "Myanma Kyat", 0], ["MNT", "₮", "Mongolian Tugrik", 0], ["MOP", "MOP$", "Macanese Pataca", 2], ["MUR", "MURs", "Mauritian Rupee", 0], ["MXN", "MX$", "Mexican Peso", 2], ["MYR", "RM", "Malaysian Ringgit", 2], ["MZN", "MTn", "Mozambican Metical", 2], ["NAD", "N$", "Namibian Dollar", 2], ["NGN", "₦", "Nigerian Naira", 2], ["NIO", "C$", "Nicaraguan Córdoba", 2], ["NOK", "Nkr", "Norwegian Krone", 2], ["NPR", "NPRs", "Nepalese Rupee", 2], ["NZD", "NZ$", "New Zealand Dollar", 2], ["OMR", "OMR", "Omani Rial", 3], ["PAB", "B/.", "Panamanian Balboa", 2], ["PEN", "S/.", "Peruvian Nuevo Sol", 2], ["PHP", "₱", "Philippine Peso", 2], ["PKR", "PKRs", "Pakistani Rupee", 0], ["PLN", "zł", "Polish Zloty", 2], ["PYG", "₲", "Paraguayan Guarani", 0], ["QAR", "QR", "Qatari Rial", 2], ["RON", "RON", "Romanian Leu", 2], ["RSD", "din.", "Serbian Dinar", 0], ["RUB", "₽", "Russian Ruble", 2], ["RWF", "RWF", "Rwandan Franc", 0], ["SAR", "SR", "Saudi Riyal", 2], ["SDG", "SDG", "Sudanese Pound", 2], ["SEK", "Skr", "Swedish Krona", 2], ["SGD", "S$", "Singapore Dollar", 2], ["SOS", "Ssh", "Somali Shilling", 0], ["SYP", "SY£", "Syrian Pound", 0], ["THB", "฿", "Thai Baht", 2], ["TND", "DT", "Tunisian Dinar", 3], ["TOP", "T$", "Tongan Paʻanga", 2], ["TRY", "₺", "Turkish Lira", 2], ["TTD", "TT$", "Trinidad and Tobago Dollar", 2], ["TWD", "NT$", "New Taiwan Dollar", 2], ["TZS", "TSh", "Tanzanian Shilling", 0], ["UAH", "₴", "Ukrainian Hryvnia", 2], ["UGX", "USh", "Ugandan Shilling", 0], ["UYU", "$U", "Uruguayan Peso", 2], ["UZS", "UZS", "Uzbekistan Som", 0], ["VEF", "Bs.F.", "Venezuelan Bolívar", 2], ["VND", "₫", "Vietnamese Dong", 0], ["XAF", "FCFA", "CFA Franc BEAC", 0], ["XOF", "CFA", "CFA Franc BCEAO", 0], ["YER", "﷼", "Yemeni Rial", 0], ["ZAR", "R", "South African Rand", 2], ["ZMK", "ZK", "Zambian Kwacha", 0], ["ZWL", "ZWL$", "Zimbabwean Dollar", 0]];
1741
+
1742
+ function _extends() {
1743
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
1744
+ for (var i = 1; i < arguments.length; i++) {
1745
+ var source = arguments[i];
1746
+ for (var key in source) {
1747
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1748
+ target[key] = source[key];
1749
+ }
1750
+ }
1751
+ }
1752
+ return target;
1753
+ };
1754
+ return _extends.apply(this, arguments);
1755
+ }
1756
+
1757
+ // TODO: [dev] return addCommasToAmountString internal method to encapsulate commas adding
1758
+
1759
+ class AmountUtils {
1760
+ static fiatXs(amount, code) {
1761
+ return this.fiat(amount, code, {
1762
+ extraSmallLength: true
1763
+ });
1764
+ }
1765
+
1766
+ /**
1767
+ * Universal method for rendering of fiat amounts, taking into account the rules of
1768
+ * the passed fiat currency code.
1769
+ *
1770
+ * TODO: [feature, high] remove 'number' from accepted types list task_id=1e692bcfabbe487a9d1638fc8ff17448
1771
+ * @param amount {BigNumber|number|string|null|undefined} The number value to be trimmed
1772
+ * @param currencyCode {string|null} The currency code. Can be omitted if { ticker: false } in the config
1773
+ * @param [passedParams={}] {object} Formatting parameters
1774
+ * @return {string} Formatted fiat amount string
1775
+ */
1776
+ static fiat(amount, currencyCode, passedParams = {}) {
1777
+ try {
1778
+ const params = _extends({}, this.defaultFiatParams, passedParams);
1779
+ if (this._checkIfAmountInvalid(amount, true) || typeof currencyCode !== "string") return "NULL";
1780
+ const currencySymbol = FiatCurrenciesService.getCurrencySymbolByCode(currencyCode);
1781
+ const currencyDecimalCount = FiatCurrenciesService.getCurrencyDecimalCountByCode(currencyCode);
1782
+ const trimmedByMaxDigits = BigNumber(amount).toFixed(currencyDecimalCount, BigNumber.ROUND_FLOOR);
1783
+ let processedAmount = BigNumber(trimmedByMaxDigits);
1784
+ if (params.collapsible && processedAmount.gte(BigNumber("1000000"))) {
1785
+ processedAmount = this._collapseToMillionsAndFormat(processedAmount, this.collapsedDecimalCount, params);
1786
+ } else {
1787
+ const limitResult = this._limitTotalAmountLengthIfNeeded(trimmedByMaxDigits, params);
1788
+ processedAmount = BigNumber(limitResult.processedAmount).toFormat(); // Adds commas to integer part
1789
+ }
1790
+
1791
+ // Add the currency code or currency symbol, if symbol is enabled and available
1792
+ if (params.ticker) {
1793
+ if (typeof currencySymbol === "string" && params.enableCurrencySymbols) {
1794
+ processedAmount = currencySymbol + (currencySymbol.length > 1 ? " " : "") + processedAmount;
1795
+ } else {
1796
+ processedAmount = processedAmount + " " + currencyCode;
1797
+ }
1798
+ }
1799
+ return processedAmount;
1800
+ } catch (e) {
1801
+ improveAndRethrow(e, "fiat", `Passed: ${amount}`);
1802
+ }
1803
+ }
1804
+ static cryptoWoTicker(amount, digits) {
1805
+ return this.crypto(amount, null, digits, {
1806
+ ticker: false
1807
+ });
1808
+ }
1809
+ static cryptoWoTickerXs(amount, digits) {
1810
+ return this.crypto(amount, null, digits, {
1811
+ ticker: false,
1812
+ extraSmallLength: true
1813
+ });
1814
+ }
1815
+ static cryptoXs(amount, ticker, digits) {
1816
+ return this.crypto(amount, ticker, digits, {
1817
+ extraSmallLength: true,
1818
+ periods: false
1819
+ });
1820
+ }
1821
+ static cryptoFull(amount, ticker, digits) {
1822
+ return this.crypto(amount, ticker, digits, {
1823
+ collapsible: false,
1824
+ trim: false,
1825
+ limitTotalLength: false
1826
+ });
1827
+ }
1828
+ static cryptoFullPureNumber(amount, digits) {
1829
+ return this.crypto(amount, null, digits, {
1830
+ ticker: false,
1831
+ collapsible: false,
1832
+ trim: false,
1833
+ limitTotalLength: false,
1834
+ numberPartsSeparator: false
1835
+ });
1836
+ }
1837
+
1838
+ /**
1839
+ * Universal method for rendering of crypto amounts, taking into account the rules of
1840
+ * the passed ticker. Requires the number of digits after period to be less of equal to
1841
+ * the number of digits, supported by the passed ticker.
1842
+ *
1843
+ * @param amount {BigNumber|string|null|undefined} The number value to be formatted
1844
+ * @param ticker {string|null} Coin ticker
1845
+ * @param [digits=8] {number} max digits after the dot
1846
+ * @param passedParams {object} Formatting parameters
1847
+ * @return {string} Formatted crypto amount string
1848
+ */
1849
+ static crypto(amount, ticker, digits = this.significantDecimalCount, passedParams) {
1850
+ try {
1851
+ const params = _extends({}, this.defaultCryptoParams, passedParams);
1852
+ if (this._checkIfAmountInvalid(amount) || typeof ticker !== "string" && params.ticker) return "NULL";
1853
+ let addPeriods = false;
1854
+ const amountBigNumber = BigNumber(amount);
1855
+ let processedAmount = amountBigNumber.toFixed(digits, BigNumber.ROUND_FLOOR);
1856
+ processedAmount = this.removeRedundantRightZerosFromNumberString(processedAmount);
1857
+ const originalAmountDecimalPlaces = BigNumber(processedAmount).decimalPlaces();
1858
+ // Check decimal count and throw an error, if the amount has more decimal digits than supported by the asset
1859
+ if (originalAmountDecimalPlaces > digits) {
1860
+ const errorMessage = `An attempt to render a crypto value with too many digits after period was made: ${amount}, allowed digits: ${digits}. This is a no-op, since the logical and visually rendered values would differ, which is not acceptable for crypto amounts. Please trim the amount before rendering, using the trimCryptoAmountByCoin(amount, coin) method.`;
1861
+ // throw new Error(errorMessage);
1862
+ // eslint-disable-next-line no-console
1863
+ console.log(errorMessage, "crypto");
1864
+ }
1865
+
1866
+ // Shortening the value to general significant number of digits after period
1867
+ if (params.trim) {
1868
+ processedAmount = this.removeRedundantRightZerosFromNumberString(amountBigNumber.toFixed(this.significantDecimalCount, BigNumber.ROUND_FLOOR));
1869
+ addPeriods = originalAmountDecimalPlaces > this.significantDecimalCount;
1870
+ }
1871
+ const limitResult = this._limitTotalAmountLengthIfNeeded(processedAmount, params);
1872
+ processedAmount = limitResult.processedAmount;
1873
+ addPeriods || (addPeriods = limitResult.addPeriods);
1874
+ let wereMillionsCollapsed = false;
1875
+ if (params.collapsible && amountBigNumber.gte("1000000")) {
1876
+ // Collapse the 1M+ amounts if applicable
1877
+ processedAmount = this._collapseToMillionsAndFormat(BigNumber(processedAmount), this.collapsedDecimalCount, params);
1878
+ wereMillionsCollapsed = true;
1879
+ } else if (params.numberPartsSeparator) {
1880
+ // Add separators to integer part of the amount
1881
+ processedAmount = BigNumber(processedAmount).toFormat();
1882
+ }
1883
+
1884
+ // Adding periods, if the amount was shortened
1885
+ if (params.periods && addPeriods && !wereMillionsCollapsed) {
1886
+ processedAmount = processedAmount + this.periods;
1887
+ }
1888
+
1889
+ // Adding an adaptive (printable/full) ticker
1890
+ if (params.ticker && ticker) {
1891
+ processedAmount = processedAmount + " " + ticker;
1892
+ }
1893
+ return processedAmount;
1894
+ } catch (e) {
1895
+ improveAndRethrow(e, "crypto", `Passed: ${amount}, ${ticker}, ${digits}`);
1896
+ }
1897
+ }
1898
+ static _checkIfAmountInvalid(amount, allowNumbers = false) {
1899
+ return amount == null || amount === "" || !BigNumber.isBigNumber(amount) && typeof amount !== "string" && (!allowNumbers || typeof amount !== "number");
1900
+ }
1901
+
1902
+ /**
1903
+ * Trims all digits after period that exceed the number of digits provided.
1904
+ * Use this everywhere when calculating some amount value to ensure the result is correct in terms
1905
+ * of max digits allowed by specific currency.
1906
+ *
1907
+ * @param amount {BigNumber|number|string|null|undefined} The number value to be trimmed.
1908
+ * HEX strings also allowed "0x..." and JS hex numbers
1909
+ * @param digits {number} allowed digits
1910
+ * @return {string|null} String with trimmed number or null for invalid amount
1911
+ */
1912
+ static trim(amount, digits) {
1913
+ try {
1914
+ if (this._checkIfAmountInvalid(amount, true)) return null;
1915
+ return BigNumber(amount).toFixed(digits, BigNumber.ROUND_FLOOR);
1916
+ } catch (e) {
1917
+ improveAndRethrow(e, "trim", `Passed: ${amount}, ${digits}`);
1918
+ }
1919
+ }
1920
+
1921
+ /**
1922
+ * @param amount {BigNumber|number|string|null|undefined} The number value to be trimmed.
1923
+ * HEX strings also allowed "0x..." and JS hex numbers
1924
+ * @return {string|null}
1925
+ */
1926
+ static intStr(amount) {
1927
+ return this.trim(amount, 0);
1928
+ }
1929
+
1930
+ /**
1931
+ * Shortens the line length by using a "1.52M" representation of big amounts.
1932
+ *
1933
+ * @param amountBigNumber {BigNumber} The number value to be trimmed
1934
+ * @param decimalCount {number} The number of digits after period to keep in millions representation
1935
+ * @param params {object} params object
1936
+ * @return {string} A shortened string, converted into "millions" format, if the amount exceeds 1 million
1937
+ */
1938
+ static _collapseToMillionsAndFormat(amountBigNumber, decimalCount, params = {}) {
1939
+ try {
1940
+ // TODO: [feature, moderate] use local format here - take from JS locales (comma/dot etc.)
1941
+ const millionBigNumber = BigNumber("1000000");
1942
+ const millions = amountBigNumber.div(millionBigNumber).toFixed(decimalCount, BigNumber.ROUND_FLOOR);
1943
+ const limitedResult = this._limitTotalAmountLengthIfNeeded(millions, params);
1944
+ const formatted = BigNumber(limitedResult.processedAmount).toFormat();
1945
+ return formatted + "M";
1946
+ } catch (e) {
1947
+ improveAndRethrow(e, "_collapseAmountAndFormat", `Passed: ${amountBigNumber.toFixed()}, ${decimalCount}`);
1948
+ }
1949
+ }
1950
+
1951
+ /**
1952
+ * @param amountString {string} The amount to be restricted by length
1953
+ * @param params {object} Params object used for formatting
1954
+ * @return {{processedAmount:string, addPeriods: boolean}} A shortened string
1955
+ */
1956
+ static _limitTotalAmountLengthIfNeeded(amountString, params) {
1957
+ try {
1958
+ let addPeriods = false;
1959
+ if (params.limitTotalLength || params.extraSmallLength) {
1960
+ const maxLength = params.extraSmallLength ? this.extraSmallMaxTotalLength : this.maxTotalLength;
1961
+ if (amountString.length > maxLength) {
1962
+ const delta = amountString.length - maxLength;
1963
+ const currentDecimalsCount = BigNumber(amountString).decimalPlaces();
1964
+ const newDecimalCount = currentDecimalsCount - delta;
1965
+ amountString = BigNumber(amountString).toFixed(newDecimalCount > 2 ? newDecimalCount : 2, BigNumber.ROUND_FLOOR);
1966
+ addPeriods = currentDecimalsCount > newDecimalCount;
1967
+ }
1968
+ }
1969
+ return {
1970
+ addPeriods: addPeriods,
1971
+ processedAmount: amountString
1972
+ };
1973
+ } catch (e) {
1974
+ improveAndRethrow(e, "_limitTotalAmountLengthIfNeeded", `Passed: ${amountString}, ${params}`);
1975
+ }
1976
+ }
1977
+
1978
+ /**
1979
+ * Safely composes rate string (handles small/big rates)
1980
+ *
1981
+ * @param leftTicker {string}
1982
+ * @param rightTicker {string}
1983
+ * @param rate {number|string|BigNumber}
1984
+ * @param [rightCurrencyDigitsAfterDots=8] {number}
1985
+ * @return {string}
1986
+ */
1987
+ static composeRateText(leftTicker, rightTicker, rate, rightCurrencyDigitsAfterDots = this.significantDecimalCount) {
1988
+ try {
1989
+ /* Here we try to calculate a clear rate for the user. The difficulty is that the rate value can be pretty
1990
+ * small as some coins have significantly higher price than the other. For such cases we calculate
1991
+ * not the "1 <coin_A> is X <coin B>" but "Y <coin_A> is X <coin B>" where Y is one of the powers of 100.
1992
+ */
1993
+ let leftNumber = BigNumber("1");
1994
+ const multiplier = BigNumber("100");
1995
+ const maxAttemptsToGetRate = 10;
1996
+ let right = null;
1997
+ const rateBigNumber = BigNumber(rate);
1998
+ for (let i = 0; i < maxAttemptsToGetRate; ++i) {
1999
+ const rightNumberAttempt = rateBigNumber.times(leftNumber).toFixed(rightCurrencyDigitsAfterDots, BigNumber.ROUND_FLOOR);
2000
+ if (!BigNumber(rightNumberAttempt).eq(BigNumber("0"))) {
2001
+ right = BigNumber(rightNumberAttempt);
2002
+ break;
2003
+ } else {
2004
+ leftNumber = leftNumber.times(multiplier);
2005
+ }
2006
+ }
2007
+ const leftAmountString = AmountUtils.intStr(leftNumber);
2008
+ const rightAmountString = right != null ? right.toFixed(rightCurrencyDigitsAfterDots, BigNumber.ROUND_FLOOR) : null;
2009
+ return `${leftAmountString} ${leftTicker} ~ ${rightAmountString != null ? rightAmountString : "?"} ${rightTicker}`;
2010
+ } catch (e) {
2011
+ // eslint-disable-next-line no-console
2012
+ console.log("composeRateText", e);
2013
+ }
2014
+ return "-";
2015
+ }
2016
+
2017
+ /**
2018
+ * @param numberAsAString {string}
2019
+ * @return {string}
2020
+ */
2021
+ static removeRedundantRightZerosFromNumberString(numberAsAString) {
2022
+ try {
2023
+ var _right2;
2024
+ const parts = ("" + numberAsAString).split(".");
2025
+ let right = parts[1];
2026
+ while ((_right = right) != null && _right.length && right[right.length - 1] === "0") {
2027
+ var _right;
2028
+ right = right.slice(0, right.length - 1);
2029
+ }
2030
+ return `${parts[0]}${(_right2 = right) != null && _right2.length ? `.${right}` : ""}`;
2031
+ } catch (e) {
2032
+ improveAndRethrow(e, "removeRedundantRightZerosFromNumberString", `Passed: ${numberAsAString}`);
2033
+ }
2034
+ }
2035
+ }
2036
+ AmountUtils.significantDecimalCount = 8;
2037
+ AmountUtils.collapsedDecimalCount = 2;
2038
+ AmountUtils.maxTotalLength = 12;
2039
+ AmountUtils.extraSmallMaxTotalLength = 9;
2040
+ // >=10 breaks transactions list (mobile) and it is hard to avoid this
2041
+ AmountUtils.periods = "..";
2042
+ AmountUtils.defaultFiatParams = {
2043
+ ticker: true,
2044
+ // If true, currency code will be shown
2045
+ enableCurrencySymbols: true,
2046
+ // Enables currency symbols where available. Requires "ticker: true"
2047
+ collapsible: true,
2048
+ // Enables minimization of amounts over 1 million (example: 1.52M)
2049
+ limitTotalLength: true,
2050
+ // Limits the total amount length to maxTotalLength
2051
+ extraSmallLength: false // Limits the total amount length to extraSmallMaxTotalLength
2052
+ };
2053
+ AmountUtils.defaultCryptoParams = {
2054
+ ticker: true,
2055
+ // If true, asset ticker will be shown
2056
+ collapsible: true,
2057
+ // Enables minimization of amounts over 1 million (example: 1.52M)
2058
+ trim: true,
2059
+ // Cuts the right part of the amount if necessary, and adds ".." in the end
2060
+ limitTotalLength: true,
2061
+ // Limits the total amount length to maxTotalLength
2062
+ extraSmallLength: false,
2063
+ // Limits the total amount length to extraSmallMaxTotalLength
2064
+ periods: true,
2065
+ // Whether we add periods ("..") as suffix for trimmed numbers
2066
+ numberPartsSeparator: true // Whether we add separators e.g. for 1000000 -> 1,000,000
2067
+ };
2068
+
2069
+ class Blockchain {
2070
+ /**
2071
+ * @param name {string} latin printable name of blockchain
2072
+ * @param supportedProtocols {Protocol[]}
2073
+ */
2074
+ constructor(name, supportedProtocols = []) {
2075
+ this.name = name;
2076
+ this.supportedProtocols = supportedProtocols;
2077
+ }
2078
+ }
2079
+
2080
+ class Protocol {
2081
+ constructor(protocolName) {
2082
+ this.protocol = protocolName;
2083
+ }
2084
+ }
2085
+
2086
+ /**
2087
+ * The model for cryptocurrency coins.
2088
+ *
2089
+ * WARNING: this class should not be instantiated directly. Use only predefined singleton Coin (or descendants) instances.
2090
+ */
2091
+ class Coin {
2092
+ /**
2093
+ * Creates new coin
2094
+ *
2095
+ * @param latinName {string} the coin name in latin symbols like "Bitcoin"
2096
+ * @param ticker {string} the coin symbol/ticker/code like 'BTC'. Always upper case. A unique coin identifier
2097
+ * @param tickerPrintable {string} ticker but in printable format. Useful for tokens based on external blockchains
2098
+ * like ERC20 or TRC20. It is not friendly to display USDTERC20 or BUSDTRC20 - more neat options are just
2099
+ * USDT and BUSD. Note that you should always care about user's understanding of what coin he/she is working
2100
+ * with as printable ticker for USDTERC20 and USDTTRC20 are the same.
2101
+ * @param digitsCountAfterComma {number} count of digits after the comma. E.g. 8 for bitcoin
2102
+ * @param maxValue {number|null} max possible value for cryptocurrency. Null means that the currency has no max possible value
2103
+ * @param atomName {string} name of the coin's atomic value. Like 'satoshi' for bitcoin
2104
+ * @param mainnet {Network} main network for this coin
2105
+ * @param testnet {Network} test network for this coin
2106
+ * @param minConfirmations {number} min confirmations count to treat the coin's transaction confirmed
2107
+ * @param payableEntityStringForFeeRate {string|null} the payable fee entity like byte for bitcoin or gas for ether if present
2108
+ * @param feeOptionsTimeStringsSortedDesc {string[]} array of 4 strings for fee options when sending coins. Should be sorted from the highest time to the smallest
2109
+ * @param feeRatesExpirationTimeMs {number} number of milliseconds to treat the fee rates as expired
2110
+ * @param blockchain {Blockchain} blockchain object
2111
+ * @param [protocol] {Protocol|null} token/coin protocol if relevant
2112
+ * @param [tokenAddress] {string|null} address of contract of this token (if the coin is token)
2113
+ * @param [doesUseLowerCaseAddresses] {boolean} flag to clarify whether we can use lower case addresses to ensure more robust comparisons
2114
+ * @param [doesUseOutputs=false] {boolean} true if this coin uses inputs/outputs concept and false if it uses just balances
2115
+ */
2116
+ constructor(latinName, ticker, tickerPrintable, digitsCountAfterComma, maxValue, atomName, mainnet, testnet, minConfirmations, payableEntityStringForFeeRate, feeOptionsTimeStringsSortedDesc, feeRatesExpirationTimeMs, blockchain, protocol = null, tokenAddress = null, doesUseLowerCaseAddresses = true, doesUseOutputs = false) {
2117
+ this.latinName = latinName;
2118
+ this.ticker = ticker;
2119
+ this.tickerPrintable = tickerPrintable;
2120
+ this.digits = digitsCountAfterComma;
2121
+ this.maxValue = maxValue;
2122
+ this.atomName = atomName;
2123
+ this.mainnet = mainnet;
2124
+ this.testnet = testnet;
2125
+ this.minConfirmations = minConfirmations;
2126
+ this.payableEntityStringForFeeRate = payableEntityStringForFeeRate;
2127
+ this.feeOptionsTimeStringsSortedDesc = feeOptionsTimeStringsSortedDesc;
2128
+ this.feeRatesExpirationTimeMs = feeRatesExpirationTimeMs;
2129
+ this.protocol = protocol;
2130
+ this.blockchain = blockchain;
2131
+ // TODO: [bug, critical] use testnet property for testnet contract address as it blocks the app work in testnets
2132
+ this.tokenAddress = tokenAddress;
2133
+ this.feeCoin = this;
2134
+ this._significantDigits = 8;
2135
+ this.doesUseLowerCaseAddresses = doesUseLowerCaseAddresses;
2136
+ this.doesUseOutputs = doesUseOutputs;
2137
+ }
2138
+
2139
+ /**
2140
+ * Sets fee coin
2141
+ *
2142
+ * @param feeCoin {Coin} some tokens use another coin to charge transaction fee as they work on top of some external
2143
+ * blockchain. So pass here the coin the token uses for fee charging. Like for ERC20 token the fee coin is ETH.
2144
+ * By default, the creating coin will be set as a value for this field.
2145
+ */
2146
+ setFeeCoin(feeCoin) {
2147
+ this.feeCoin = feeCoin;
2148
+ }
2149
+
2150
+ /**
2151
+ * Checks whether this coin uses another coin (blockchain) to charge fee for transactions (means works on base of
2152
+ * some external blockchain).
2153
+ *
2154
+ * @return {boolean} true if this coin uses external blockchain to perform transactions and charge fee
2155
+ */
2156
+ doesUseDifferentCoinFee() {
2157
+ return this.feeCoin !== this;
2158
+ }
2159
+
2160
+ /**
2161
+ * Converts the given atoms string/number to string representing the same amount in coin itself - floating point number
2162
+ *
2163
+ * @param atoms {string} atoms positive integer amount
2164
+ * @return {string} coin amount floating point number as a string
2165
+ */
2166
+ atomsToCoinAmount(atoms) {
2167
+ throw new Error("Not implemented in base Coin");
2168
+ }
2169
+
2170
+ /**
2171
+ * Converts the given coins amount string/number to string representing the same amount in coin atoms - integer number
2172
+ *
2173
+ * @param coinsAmount {string} coins positive floating point amount
2174
+ * @return {string} coin atoms amount integer number as a string
2175
+ */
2176
+ coinAmountToAtoms(coinsAmount) {
2177
+ throw new Error("Not implemented in base Coin");
2178
+ }
2179
+
2180
+ /**
2181
+ * Composes URL to view the tx with given id in the external blockchain explorer
2182
+ *
2183
+ * @param txId {string} id of transaction
2184
+ * @return {string} URL string
2185
+ */
2186
+ composeUrlToTransactionExplorer(txId) {
2187
+ throw new Error("Not implemented in base Coin");
2188
+ }
2189
+
2190
+ /**
2191
+ * Most of the cryptocurrencies has specific fee rate or fee price metric. This value usually has specific measure
2192
+ * like satoshi/byte or gWei/gas. This function adds the described denomination string to the given amount
2193
+ * as a suffix and returns the result string ready to be show to a user.
2194
+ *
2195
+ * @param coinAtomsString {string} coin atoms positive integer amount
2196
+ * @return {string} string of coin amount and fee rate units
2197
+ */
2198
+ coinAtomsFeeRateToCommonlyUsedAmountFormatWithDenominationString(coinAtomsString) {
2199
+ throw new Error("Not implemented in base Coin");
2200
+ }
2201
+
2202
+ /**
2203
+ * Check whether this coin support transaction prioritisation during the sending process.
2204
+ *
2205
+ * @return {boolean} true if support transaction prioritisation and false otherwise
2206
+ */
2207
+ doesSupportTransactionPrioritisation() {
2208
+ return Array.isArray(this.feeOptionsTimeStringsSortedDesc);
2209
+ }
2210
+ tickerAndProtocol() {
2211
+ try {
2212
+ var _ref;
2213
+ return `${this.tickerPrintable}${this.protocol ? (_ref = " " + this.protocol.protocol) != null ? _ref : "" : ""}`;
2214
+ } catch (e) {
2215
+ improveAndRethrow(e, "tickerAndProtocol");
2216
+ }
2217
+ }
2218
+ }
2219
+
2220
+ /**
2221
+ * TODO: [tests, critical] Ued by payments logic
2222
+ *
2223
+ * Simple cache based on Map.
2224
+ * Provides ability to store event-dependent data.
2225
+ */
2226
+ class Cache {
2227
+ /**
2228
+ * @param eventBus {EventBus} EventBus.js lib instance
2229
+ * @param [noSessionEvents=[]] {string[]} array of events that will be treated as "no session"
2230
+ */
2231
+ constructor(eventBus, noSessionEvents = []) {
2232
+ this._cache = new Map();
2233
+ this._eventDependentDataKeys = [];
2234
+ this._noSessionEvents = noSessionEvents;
2235
+ this._eventBus = eventBus;
2236
+ }
2237
+ _setupIntervalClearingExpired() {
2238
+ let _cleaner = function cleaner() {
2239
+ try {
2240
+ for (const key of this._cache.keys()) {
2241
+ const item = this._cache.get(key);
2242
+ if (item && item.ttlMs && item.addedMsTimestamp + item.ttlMs < Date.now()) {
2243
+ this._cache.delete(key);
2244
+ }
2245
+ }
2246
+ } catch (e) {
2247
+ improveAndRethrow(e, "_intervalClearingExpiredCache");
2248
+ }
2249
+ };
2250
+ _cleaner = _cleaner.bind(this);
2251
+ setInterval(_cleaner, 1000);
2252
+ }
2253
+
2254
+ /**
2255
+ * Puts data to cache
2256
+ *
2257
+ * @param key {string} string key for this data
2258
+ * @param data {any} any data
2259
+ * @param ttlMs {number|null} optional milliseconds number for cache lifetime
2260
+ * @throws {Error} when the data is null/undefined because these values for data are reserved for internal logic
2261
+ */
2262
+ put(key, data, ttlMs = null) {
2263
+ try {
2264
+ if (typeof key !== "string" || data == null) {
2265
+ throw new Error(`Trying to cache corrupted data: ${key}, ${data}`);
2266
+ }
2267
+ this._cache.set(key, {
2268
+ data: data,
2269
+ addedMsTimestamp: Date.now(),
2270
+ ttlMs: ttlMs
2271
+ });
2272
+ } catch (e) {
2273
+ improveAndRethrow(e, "cache.put");
2274
+ }
2275
+ }
2276
+ putSessionDependentData(key, data, ttlMs = null) {
2277
+ this._putEventDependentData(key, data, this._noSessionEvents, ttlMs);
2278
+ }
2279
+
2280
+ /**
2281
+ * Puts data to cache and adds its key to list of keys that should be related by each of given events.
2282
+ *
2283
+ * @param key {string} key for cache
2284
+ * @param data {any} any caching data
2285
+ * @param events {string[]} list of events forcing putting data to be removed when triggered
2286
+ * @param ttlMs {|null} optional time to live for this cache item
2287
+ * @throws {Error} when the data is null/undefined because these values for data are reserved for internal logic
2288
+ */
2289
+ putEventDependentData(key, data, events, ttlMs = null) {
2290
+ this._putEventDependentData(key, data, events, ttlMs);
2291
+ }
2292
+ _putEventDependentData(key, data, events, ttlMs = null) {
2293
+ try {
2294
+ if (typeof key !== "string" || data == null) {
2295
+ throw new Error(`Trying to cache corrupted data: ${key}, ${data}`);
2296
+ }
2297
+ this._cache.set(key, {
2298
+ data: data,
2299
+ addedMsTimestamp: Date.now(),
2300
+ ttlMs: ttlMs
2301
+ });
2302
+ for (let event of events) {
2303
+ const eventAndKeys = this._eventDependentDataKeys.find(item => item[0] === event);
2304
+ if (eventAndKeys) {
2305
+ eventAndKeys.push(key);
2306
+ } else {
2307
+ this._eventDependentDataKeys.push([event, key]);
2308
+ this._eventBus.addEventListener(event, () => {
2309
+ try {
2310
+ const keys = this._eventDependentDataKeys.find(item => item[0] === event);
2311
+ (keys != null ? keys : [event]).slice(1).forEach(key => this._cache.delete(key));
2312
+ } catch (e) {
2313
+ Logger.logError(e, "cache.removing-for-event", `Event: ${event}`);
2314
+ }
2315
+ });
2316
+ }
2317
+ }
2318
+ } catch (e) {
2319
+ improveAndRethrow(e, "cache.putEventDependentData");
2320
+ }
2321
+ }
2322
+
2323
+ // TODO: [feature, low] add clearing of expired data by schedule
2324
+ get(key) {
2325
+ try {
2326
+ const item = this._cache.get(key);
2327
+ if (item) {
2328
+ if (item.addedMsTimestamp && item.ttlMs !== null && item.addedMsTimestamp + item.ttlMs < Date.now()) {
2329
+ this._cache.delete(key);
2330
+ return null;
2331
+ } else {
2332
+ return item.data;
2333
+ }
2334
+ }
2335
+ return null;
2336
+ } catch (e) {
2337
+ improveAndRethrow(e, "cache.get");
2338
+ }
2339
+ }
2340
+ getLastUpdateTimestamp(key) {
2341
+ var _this$_cache$get$adde, _this$_cache$get;
2342
+ return (_this$_cache$get$adde = (_this$_cache$get = this._cache.get(key)) == null ? void 0 : _this$_cache$get.addedMsTimestamp) != null ? _this$_cache$get$adde : null;
2343
+ }
2344
+
2345
+ /**
2346
+ * Updates the timestamp of the last update for specified key to the provided value.
2347
+ * Can be useful when TTL is controlled outside this class.
2348
+ *
2349
+ * @param key {string}
2350
+ * @param timestamp {number}
2351
+ * @return {boolean}
2352
+ */
2353
+ setLastUpdateTimestamp(key, timestamp) {
2354
+ try {
2355
+ const item = this._cache.get(key);
2356
+ if (item != null && typeof timestamp === "number") {
2357
+ this._cache.set(key, _extends({}, item, {
2358
+ addedTimestampMs: timestamp
2359
+ }));
2360
+ return true;
2361
+ }
2362
+ return false;
2363
+ } catch (e) {
2364
+ improveAndRethrow("cache.setLastUpdateTimestamp");
2365
+ }
2366
+ }
2367
+ invalidate(key) {
2368
+ try {
2369
+ this._cache.delete(key);
2370
+ } catch (e) {
2371
+ improveAndRethrow(e, "cache.invalidate");
2372
+ }
2373
+ }
2374
+ invalidateContaining(keyPart) {
2375
+ if (typeof keyPart !== "string" || keyPart === "") {
2376
+ throw new Error("Trying to invalidate containing wrong key or empty key: " + keyPart);
2377
+ }
2378
+ try {
2379
+ const matchedKeys = Array.from(this._cache.keys()).filter(key => typeof key === "string" && new RegExp(keyPart).test(key));
2380
+ for (let i = 0; i < matchedKeys.length; ++i) {
2381
+ this._cache.delete(matchedKeys[i]);
2382
+ }
2383
+ } catch (e) {
2384
+ improveAndRethrow(e, "invalidateContaining");
2385
+ }
2386
+ }
2387
+ clear() {
2388
+ this._cache.clear();
2389
+ this._sessionDependentDataKeys = [];
2390
+ }
2391
+
2392
+ /**
2393
+ * Saves given data string to persistent cache.
2394
+ * NOTE: we have no TTL here, implement if needed.
2395
+ *
2396
+ * WARNING: use only when really needed and don't store big data as we use localStorage
2397
+ * under the hood and its capacity is restricted.
2398
+ *
2399
+ * @param uniqueKey {string} the key should be unique
2400
+ * @param data {string} only string data allowed
2401
+ */
2402
+ putClientPersistentData(uniqueKey, data) {
2403
+ try {
2404
+ if (typeof window !== "undefined") {
2405
+ localStorage.setItem(uniqueKey, data);
2406
+ }
2407
+ } catch (e) {
2408
+ improveAndRethrow(e, "cache.putClientPersistentData");
2409
+ }
2410
+ }
2411
+
2412
+ /**
2413
+ * @param uniqueKey {string}
2414
+ * @return {string|null}
2415
+ */
2416
+ getClientPersistentData(uniqueKey) {
2417
+ try {
2418
+ if (typeof window !== "undefined") {
2419
+ return localStorage.getItem(uniqueKey);
2420
+ }
2421
+ return null;
2422
+ } catch (e) {
2423
+ improveAndRethrow(e, "cache.getClientPersistentData");
2424
+ }
2425
+ }
2426
+
2427
+ /**
2428
+ * Only makes effect if the TTL is not null.
2429
+ *
2430
+ * @param key {string}
2431
+ * @param ttlMs {number|null}
2432
+ */
2433
+ markCacheItemAsExpiredButDontRemove(key, ttlMs = null) {
2434
+ try {
2435
+ const item = this._cache.get(key);
2436
+ const ttlFinalMs = ttlMs != null ? ttlMs : item == null ? void 0 : item.ttlMs;
2437
+ if (item != null && ttlFinalMs) {
2438
+ this._cache.set(key, {
2439
+ data: item.data,
2440
+ addedMsTimestamp: Date.now() - ttlFinalMs - 1,
2441
+ ttlMs: ttlFinalMs
2442
+ });
2443
+ }
2444
+ } catch (e) {
2445
+ improveAndRethrow(e, "cache.markCacheItemAsExpiredButDontRemove");
2446
+ }
2447
+ }
2448
+ }
2449
+
2450
+ function postponeExecution(execution, timeoutMS = 1000) {
2451
+ return new Promise((resolve, reject) => {
2452
+ setTimeout(async () => {
2453
+ try {
2454
+ resolve(await execution());
2455
+ } catch (e) {
2456
+ reject(e);
2457
+ }
2458
+ }, timeoutMS);
2459
+ });
2460
+ }
2461
+
2462
+ class AxiosAdapter {
2463
+ static async call(method, ...args) {
2464
+ return await axios[method](...args);
2465
+ }
2466
+ static async get(...args) {
2467
+ return await axios.get(...args);
2468
+ }
2469
+ static async post(...args) {
2470
+ return await axios.post(...args);
2471
+ }
2472
+ static async put(...args) {
2473
+ return await axios.put(...args);
2474
+ }
2475
+ static async delete(...args) {
2476
+ return await axios.delete(...args);
2477
+ }
2478
+ static async patch(...args) {
2479
+ return await axios.patch(...args);
2480
+ }
2481
+ static async options(...args) {
2482
+ return await axios.options(...args);
2483
+ }
2484
+ static async head(...args) {
2485
+ return await axios.head(...args);
2486
+ }
2487
+ }
2488
+
2489
+ class EmailsApi {
2490
+ static async sendEmail(subject, body) {
2491
+ try {
2492
+ const url = `${window.location.protocol + "//" + window.location.host}/api/v1/${this.serverEndpointEntity}`;
2493
+ await axios.post(url, {
2494
+ subject,
2495
+ body
2496
+ });
2497
+ } catch (e) {
2498
+ improveAndRethrow(e, "sendEmail", subject + body);
2499
+ }
2500
+ }
2501
+ }
2502
+ EmailsApi.serverEndpointEntity = "emails";
2503
+
2504
+ /**
2505
+ * This util helps to avoid duplicated calls to a shared resource.
2506
+ * It tracks is there currently active calculation for the specific cache id and make all other requests
2507
+ * with the same cache id waiting for this active calculation to be finished. When the calculation ends
2508
+ * the resolver allows all the waiting requesters to get the data from cache and start their own calculations.
2509
+ *
2510
+ * This class should be instantiated inside some other service where you need to request some resource concurrently.
2511
+ * Rules:
2512
+ * 1. When you need to make a request inside your main service call 'getCachedOrWaitForCachedOrAcquireLock'
2513
+ * on the instance of this class and await for the result. If the flag allowing to start calculation is true
2514
+ * then you can request data inside your main service. Otherwise you should use the cached data as an another
2515
+ * requester just finished the most resent requesting and there is actual data in the cache that
2516
+ * is returned to you here.
2517
+ * 1.1 Also you can acquire a lock directly if you don't want to get cached data. Use the corresponding method 'acquireLock'.
2518
+ *
2519
+ * 2. If you start requesting (when you successfully acquired the lock) then after receiving the result of your
2520
+ * requesting you should call the 'saveCachedData' so the retrieved data will appear in the cache.
2521
+ *
2522
+ * 3. If you successfully acquired the lock then you should after calling the 'saveCachedData' call
2523
+ * the 'releaseLock' - this is mandatory to release the lock and allow other requesters to perform their requests.
2524
+ * WARNING: If for any reason you forget to call this method then this class instance will wait perpetually for
2525
+ * the lock releasing and all your attempts to request the data will constantly fail. So usually call it
2526
+ * inside the 'finally' block.
2527
+ *
2528
+ * TODO: [tests, critical++] add unit tests - massively used logic and can produce sophisticated concurrency bugs
2529
+ */
2530
+ class CacheAndConcurrentRequestsResolver {
2531
+ /**
2532
+ * @param bio {string} unique identifier for the exact service
2533
+ * @param cache {Cache} cache
2534
+ * @param cacheTtl {number|null} time to live for cache ms. 0 or null means the cache cannot expire
2535
+ * @param [maxCallAttemptsToWaitForAlreadyRunningRequest=100] {number} number of request allowed to do waiting for
2536
+ * result before we fail the original request. Use custom value only if you need to make the attempts count
2537
+ * and polling interval changes.
2538
+ * @param [timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished=1000] {number}
2539
+ * timeout ms for polling for a result. if you change maxCallAttemptsToWaitForAlreadyRunningRequest
2540
+ * then this parameter maybe also require the custom value.
2541
+ * @param [removeExpiredCacheAutomatically=true] {boolean}
2542
+ */
2543
+ constructor(bio, cache, cacheTtl, removeExpiredCacheAutomatically = true, maxCallAttemptsToWaitForAlreadyRunningRequest = 100, timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished = 1000) {
2544
+ if (cacheTtl != null && cacheTtl < timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished * 2) {
2545
+ /*
2546
+ * During the lifetime of this service e.g. if the data is being retrieved slowly we can get
2547
+ * RACE CONDITION when we constantly retrieve data and during retrieval it is expired, so we are trying
2548
+ * to retrieve it again and again.
2549
+ * We have a protection mechanism that we will wait no more than
2550
+ * maxCallAttemptsToWaitForAlreadyRunningRequest * timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished
2551
+ * but this additional check is aimed to reduce potential loading time for some requests.
2552
+ */
2553
+ throw new Error(`DEV: Wrong parameters passed to construct ${bio} - TTL ${cacheTtl} should be 2 times greater than ${timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished}`);
2554
+ }
2555
+ this._bio = bio;
2556
+ this._cache = cache;
2557
+ this._cacheTtlMs = cacheTtl != null ? cacheTtl : null;
2558
+ this._maxExecutionTimeMs = maxCallAttemptsToWaitForAlreadyRunningRequest * timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished;
2559
+ this._removeExpiredCacheAutomatically = removeExpiredCacheAutomatically;
2560
+ this._requestsManager = new ManagerOfRequestsToTheSameResource(bio, maxCallAttemptsToWaitForAlreadyRunningRequest, timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished);
2561
+ }
2562
+
2563
+ /**
2564
+ * When using this service this is the major method you should call to get data by cache id.
2565
+ * This method checks is there cached data and ether
2566
+ * - returns you flag that you can start requesting data from the shared resource
2567
+ * - or if there is already started calculation waits until it is finished (removed from this service)
2568
+ * and returns you the retrieved data
2569
+ * - or just returns you the cached data
2570
+ *
2571
+ * 'canStartDataRetrieval' equal true means that the lock was acquired, and you should manually call 'saveCachedData'
2572
+ * if needed and then 'releaseLock' to mark this calculation as finished so other
2573
+ * requesters can take their share of the resource.
2574
+ *
2575
+ * @param cacheId {string}
2576
+ * @return {Promise<({
2577
+ * canStartDataRetrieval: true,
2578
+ * cachedData: any,
2579
+ * lockId: string
2580
+ * }|{
2581
+ * canStartDataRetrieval: false,
2582
+ * cachedData: any
2583
+ * })>}
2584
+ */
2585
+ async getCachedOrWaitForCachedOrAcquireLock(cacheId) {
2586
+ try {
2587
+ var _cached2;
2588
+ const startedAtTimestamp = Date.now();
2589
+ let cached = this._cache.get(cacheId);
2590
+ let cachedDataBackupIsPresentButExpired = null;
2591
+ if (cached != null && !this._removeExpiredCacheAutomatically) {
2592
+ const lastUpdateTimestamp = this._cache.getLastUpdateTimestamp(cacheId);
2593
+ if ((lastUpdateTimestamp != null ? lastUpdateTimestamp : 0) + this._cacheTtlMs < Date.now()) {
2594
+ /*
2595
+ * Here we are manually clearing 'cached' value retrieved from cache to force the data loading.
2596
+ * But we save its value first to the backup variable to be able to return this value if ongoing
2597
+ * requesting fails.
2598
+ */
2599
+ cachedDataBackupIsPresentButExpired = cached;
2600
+ cached = null;
2601
+ }
2602
+ }
2603
+ let calculationId = null;
2604
+ let isRetrievedCacheExpired = true;
2605
+ let isWaitingForActiveCalculationSucceeded;
2606
+ let weStillHaveSomeTimeToProceedExecution = true;
2607
+ while (calculationId == null && cached == null && isRetrievedCacheExpired && weStillHaveSomeTimeToProceedExecution) {
2608
+ const result = await this._requestsManager.startCalculationOrWaitForActiveToFinish(cacheId);
2609
+ calculationId = typeof result === "string" ? result : null;
2610
+ isWaitingForActiveCalculationSucceeded = typeof result === "boolean" ? result : null;
2611
+ cached = this._cache.get(cacheId);
2612
+ isRetrievedCacheExpired = isWaitingForActiveCalculationSucceeded && cached == null;
2613
+ weStillHaveSomeTimeToProceedExecution = Date.now() - startedAtTimestamp < this._maxExecutionTimeMs;
2614
+ }
2615
+ if (calculationId) {
2616
+ var _cached;
2617
+ return {
2618
+ canStartDataRetrieval: true,
2619
+ cachedData: (_cached = cached) != null ? _cached : cachedDataBackupIsPresentButExpired,
2620
+ lockId: calculationId
2621
+ };
2622
+ }
2623
+ return {
2624
+ canStartDataRetrieval: false,
2625
+ cachedData: (_cached2 = cached) != null ? _cached2 : cachedDataBackupIsPresentButExpired
2626
+ };
2627
+ } catch (e) {
2628
+ improveAndRethrow(e, `${this._bio}.getCachedOrWaitForCachedOrAcquireLock`);
2629
+ }
2630
+ }
2631
+
2632
+ /**
2633
+ * Returns just the current cache value for the given id.
2634
+ * Doesn't wait for the active calculation, doesn't acquire lock, just retrieves the current cache as it is.
2635
+ *
2636
+ * @param cacheId {string}
2637
+ * @return {any}
2638
+ */
2639
+ getCached(cacheId) {
2640
+ try {
2641
+ return this._cache.get(cacheId);
2642
+ } catch (e) {
2643
+ improveAndRethrow(e, "getCached");
2644
+ }
2645
+ }
2646
+ _getTtl() {
2647
+ return this._removeExpiredCacheAutomatically ? this._cacheTtlMs : null;
2648
+ }
2649
+
2650
+ /**
2651
+ * Directly acquires the lock despite on cached data availability.
2652
+ * So if this method returns result === true you can start the data retrieval.
2653
+ *
2654
+ * @param cacheId {string}
2655
+ * @return {Promise<{ result: true, lockId: string }|{ result: false }>}
2656
+ */
2657
+ async acquireLock(cacheId) {
2658
+ try {
2659
+ return await this._requestsManager.acquireLock(cacheId);
2660
+ } catch (e) {
2661
+ improveAndRethrow(e, "acquireLock");
2662
+ }
2663
+ }
2664
+
2665
+ /**
2666
+ * This method should be called only if you acquired a lock successfully.
2667
+ *
2668
+ * If the current lock id is not equal to the passed one the passed data will be ignored.
2669
+ * Or you can do the synchronous data merging on your side and pass the
2670
+ * wasDataMergedSynchronouslyWithMostRecentCacheState=true so your data will be stored
2671
+ * despite on the lockId.
2672
+ * WARNING: you should do this only if you are sure you perform the synchronous update.
2673
+ *
2674
+ * @param cacheId {string}
2675
+ * @param lockId {string}
2676
+ * @param data {any}
2677
+ * @param [sessionDependentData=true] {boolean}
2678
+ * @param [wasDataMergedSynchronouslyWithMostRecentCacheState=false]
2679
+ */
2680
+ saveCachedData(cacheId, lockId, data, sessionDependentData = true, wasDataMergedSynchronouslyWithMostRecentCacheState = false) {
2681
+ try {
2682
+ if (wasDataMergedSynchronouslyWithMostRecentCacheState || this._requestsManager.isTheLockActiveOne(cacheId, lockId)) {
2683
+ /* We save passed data only if the <caller> has the currently acquired lockId.
2684
+ * If the passed lockId is not the active one it means that other code cleared/stopped the lock
2685
+ * acquired by the <caller> recently due to some urgent/more prior changes.
2686
+ *
2687
+ * But we allow user to pass the 'wasDataMergedSynchronouslyWithMostRecentCacheState' flag
2688
+ * that tells us that the user had taken the most recent cache value and merged his new data
2689
+ * with that cached value (AFTER possibly performing async data retrieval). This means that we
2690
+ * can ignore the fact that his lockId is no more relevant and save the passed data
2691
+ * as it is synchronously merged with the most recent cached data. (Synchronously merged means that
2692
+ * the lost update cannot occur during the merge time as JS execute the synchronous functions\
2693
+ * till the end).
2694
+ */
2695
+ if (sessionDependentData) {
2696
+ this._cache.putSessionDependentData(cacheId, data, this._getTtl());
2697
+ } else {
2698
+ this._cache.put(cacheId, data, this._getTtl());
2699
+ }
2700
+ }
2701
+ } catch (e) {
2702
+ improveAndRethrow(e, `${this._bio}.saveCachedData`);
2703
+ }
2704
+ }
2705
+
2706
+ /**
2707
+ * Should be called then and only then if you successfully acquired a lock with the lock id.
2708
+ *
2709
+ * @param cacheId {string}
2710
+ * @param lockId {string}
2711
+ */
2712
+ releaseLock(cacheId, lockId) {
2713
+ try {
2714
+ if (this._requestsManager.isTheLockActiveOne(cacheId, lockId)) {
2715
+ this._requestsManager.finishActiveCalculation(cacheId);
2716
+ }
2717
+ } catch (e) {
2718
+ improveAndRethrow(e, `${this._bio}.releaseLock`);
2719
+ }
2720
+ }
2721
+
2722
+ /**
2723
+ * Actualized currently present cached data by key. Applies the provided function to the cached data.
2724
+ *
2725
+ * @param cacheId {string} id of cache entry
2726
+ * @param synchronousCurrentCacheProcessor (function|null} synchronous function accepting cache entry. Should return
2727
+ * an object in following format:
2728
+ * {
2729
+ * isModified: boolean,
2730
+ * data: any
2731
+ * }
2732
+ * the flag signals whether data was changed during the processing or not
2733
+ * @param [sessionDependent=true] {boolean} whether to mark the cache entry as session-dependent
2734
+ */
2735
+ actualizeCachedData(cacheId, synchronousCurrentCacheProcessor, sessionDependent = true) {
2736
+ try {
2737
+ const cached = this._cache.get(cacheId);
2738
+ const result = synchronousCurrentCacheProcessor(cached);
2739
+ if (result != null && result.isModified && (result == null ? void 0 : result.data) != null) {
2740
+ if (sessionDependent) {
2741
+ this._cache.putSessionDependentData(cacheId, result == null ? void 0 : result.data, this._getTtl());
2742
+ } else {
2743
+ this._cache.put(cacheId, result == null ? void 0 : result.data, this._getTtl());
2744
+ }
2745
+
2746
+ /* Here we call the lock releasing to ensure the currently active calculation will be ignored.
2747
+ * This is needed to ensure no 'lost update'.
2748
+ * Lost update can occur if we change data in this method and after that some calculation finishes
2749
+ * having the earlier data as its base to calculate its data set result. And the earlier data
2750
+ * has no changes applied inside this method, so we will lose them.
2751
+ *
2752
+ * This is not so good solution: ideally, we should acquire lock before performing any data updating.
2753
+ * But the goal of this method is to provide an instant ability to update the cached data.
2754
+ * And if we start acquiring the lock here the data update can be postponed significantly.
2755
+ * And this kills the desired nature of this method.
2756
+ * So we better lose some data retrieval (means abusing the resource a bit) than lose
2757
+ * the instant update expected after this method execution.
2758
+ */
2759
+ this._requestsManager.finishActiveCalculation(cacheId);
2760
+ }
2761
+ } catch (e) {
2762
+ improveAndRethrow(e, `${this._bio}.actualizeCachedData`);
2763
+ }
2764
+ }
2765
+ invalidate(key) {
2766
+ this._cache.invalidate(key);
2767
+ this._requestsManager.finishActiveCalculation(key);
2768
+ }
2769
+ invalidateContaining(keyPart) {
2770
+ this._cache.invalidateContaining(keyPart);
2771
+ this._requestsManager.finishAllActiveCalculations(keyPart);
2772
+ }
2773
+ markAsExpiredButDontRemove(key) {
2774
+ if (this._removeExpiredCacheAutomatically) {
2775
+ this._cache.markCacheItemAsExpiredButDontRemove(key, this._cacheTtlMs);
2776
+ } else {
2777
+ this._cache.setLastUpdateTimestamp(key, Date.now() - this._cacheTtlMs - 1);
2778
+ }
2779
+ this._requestsManager.finishAllActiveCalculations(key);
2780
+ }
2781
+ }
2782
+
2783
+ /**
2784
+ * Util class to control access to a resource when it can be called in parallel for the same result.
2785
+ * (E.g. getting today coins-fiat rates from some API).
2786
+ */
2787
+ class ManagerOfRequestsToTheSameResource {
2788
+ /**
2789
+ * @param bio {string} resource-related identifier for logging
2790
+ * @param [maxPollsCount=100] {number} max number of attempts to wait when waiting for a lock acquisition
2791
+ * @param [timeoutDuration=1000] {number} timeout between the polls for a lock acquisition
2792
+ */
2793
+ constructor(bio, maxPollsCount = 100, timeoutDuration = 1000) {
2794
+ this.bio = bio;
2795
+ this.maxPollsCount = maxPollsCount;
2796
+ this.timeoutDuration = timeoutDuration;
2797
+ this._activeCalculationsIds = new Map();
2798
+ this._nextCalculationIds = new Map();
2799
+ }
2800
+
2801
+ /**
2802
+ * If there is no active calculation just creates uuid and returns it.
2803
+ * If there is active calculation waits until it removed from the active calculation uuid variable.
2804
+ *
2805
+ * @param requestHash {string}
2806
+ * @return {Promise<string|boolean>} returns uuid of new active calculation or true if waiting for active
2807
+ * calculation succeed or false if max attempts count exceeded
2808
+ */
2809
+ async startCalculationOrWaitForActiveToFinish(requestHash) {
2810
+ try {
2811
+ const activeCalculationIdForHash = this._activeCalculationsIds.get(requestHash);
2812
+ if (activeCalculationIdForHash == null) {
2813
+ const id = v4();
2814
+ this._activeCalculationsIds.set(requestHash, id);
2815
+ return id;
2816
+ }
2817
+ return await this._waitForCalculationIdToFinish(requestHash, activeCalculationIdForHash, 0);
2818
+ } catch (e) {
2819
+ Logger.logError(e, `startCalculationOrWaitForActiveToFinish_${this.bio}`);
2820
+ }
2821
+ return null;
2822
+ }
2823
+
2824
+ /**
2825
+ * Acquires lock to the resource by the provided hash.
2826
+ *
2827
+ * @param requestHash {string}
2828
+ * @return {Promise<{ result: true, lockId: string }|{ result: false }>} result is true if the lock is successfully
2829
+ * acquired, false if the max allowed time to wait for acquisition expired or any unexpected error occurs
2830
+ * during the waiting.
2831
+ */
2832
+ async acquireLock(requestHash) {
2833
+ try {
2834
+ var _this$_nextCalculatio;
2835
+ const activeId = this._activeCalculationsIds.get(requestHash);
2836
+ const nextId = v4();
2837
+ if (activeId == null) {
2838
+ this._activeCalculationsIds.set(requestHash, nextId);
2839
+ return {
2840
+ result: true,
2841
+ lockId: nextId
2842
+ };
2843
+ }
2844
+ const currentNext = (_this$_nextCalculatio = this._nextCalculationIds.get(requestHash)) != null ? _this$_nextCalculatio : [];
2845
+ currentNext.push(nextId);
2846
+ this._nextCalculationIds.set(requestHash, currentNext);
2847
+ const waitingResult = await this._waitForCalculationIdToFinish(requestHash, activeId, 0, nextId);
2848
+ return {
2849
+ result: waitingResult,
2850
+ lockId: waitingResult ? nextId : undefined
2851
+ };
2852
+ } catch (e) {
2853
+ improveAndRethrow(e, "acquireLock");
2854
+ }
2855
+ }
2856
+
2857
+ /**
2858
+ * Clears active calculation id.
2859
+ * WARNING: if you forget to call this method the start* one will perform maxPollsCount attempts before finishing
2860
+ * @param requestHash {string} hash of request. Helps to distinct the request for the same resource but
2861
+ * having different request parameters and hold a dedicated calculation id per this hash
2862
+ */
2863
+ finishActiveCalculation(requestHash = "default") {
2864
+ try {
2865
+ var _this$_nextCalculatio2;
2866
+ this._activeCalculationsIds.delete(requestHash);
2867
+ const next = (_this$_nextCalculatio2 = this._nextCalculationIds.get(requestHash)) != null ? _this$_nextCalculatio2 : [];
2868
+ if (next.length) {
2869
+ this._activeCalculationsIds.set(requestHash, next[0]);
2870
+ this._nextCalculationIds.set(requestHash, next.slice(1));
2871
+ }
2872
+ } catch (e) {
2873
+ improveAndRethrow(e, "finishActiveCalculation");
2874
+ }
2875
+ }
2876
+ finishAllActiveCalculations(keyPart = "") {
2877
+ try {
2878
+ Array.from(this._activeCalculationsIds.keys()).forEach(hash => {
2879
+ if (typeof hash === "string" && new RegExp(keyPart).test(hash)) {
2880
+ this.finishActiveCalculation(hash);
2881
+ }
2882
+ });
2883
+ } catch (e) {
2884
+ improveAndRethrow(e, "finishAllActiveCalculations");
2885
+ }
2886
+ }
2887
+
2888
+ /**
2889
+ * @param requestHash {string}
2890
+ * @param lockId {string}
2891
+ * @return {boolean}
2892
+ */
2893
+ isTheLockActiveOne(requestHash, lockId) {
2894
+ try {
2895
+ return this._activeCalculationsIds.get(requestHash) === lockId;
2896
+ } catch (e) {
2897
+ improveAndRethrow(e, "isTheLockActiveOne");
2898
+ }
2899
+ }
2900
+
2901
+ /**
2902
+ * @param requestHash {string}
2903
+ * @param activeCalculationId {string|null}
2904
+ * @param [attemptIndex=0] {number}
2905
+ * @param waitForCalculationId {string|null} if you want to wait for an exact id to appear as active then pass this parameter
2906
+ * @return {Promise<boolean>} true
2907
+ * - if the given calculation id is no more an active one
2908
+ * - or it is equal to waitForCalculationId
2909
+ * false
2910
+ * - if waiting period exceeds the max allowed waiting time or unexpected error occurs
2911
+ * @private
2912
+ */
2913
+ async _waitForCalculationIdToFinish(requestHash, activeCalculationId, attemptIndex = 0, waitForCalculationId = null) {
2914
+ try {
2915
+ if (attemptIndex + 1 > this.maxPollsCount) {
2916
+ // Max number of polls for active calculation id change is achieved. So we return false.
2917
+ return false;
2918
+ }
2919
+ const currentId = this._activeCalculationsIds.get(requestHash);
2920
+ if (waitForCalculationId == null ? currentId !== activeCalculationId : currentId === waitForCalculationId) {
2921
+ /* We return true depending on the usage of this function:
2922
+ * 1. if there is calculation id that we should wait for to become an active then we return true only
2923
+ * if this id becomes the active one.
2924
+ *
2925
+ * Theoretically we can fail to wait for the desired calculation id. This can be caused by wrong use of
2926
+ * this service or by any other mistakes/errors. But this waiting function will return false anyway if
2927
+ * the number of polls done exceeds the max allowed.
2928
+ *
2929
+ * 2. if we just wait for the currently active calculation id to be finished then we return true
2930
+ * when we notice that the current active id differs from the original passed into this function.
2931
+ */
2932
+ return true;
2933
+ } else {
2934
+ /* The original calculation id is still the active one, so we are scheduling a new attempt to check
2935
+ * whether the active calculation id changed or not in timeoutDuration milliseconds.
2936
+ */
2937
+ const it = this;
2938
+ return new Promise((resolve, reject) => {
2939
+ setTimeout(function () {
2940
+ try {
2941
+ resolve(it._waitForCalculationIdToFinish(requestHash, activeCalculationId, attemptIndex + 1));
2942
+ } catch (e) {
2943
+ reject(e);
2944
+ }
2945
+ }, this.timeoutDuration);
2946
+ });
2947
+ }
2948
+ } catch (e) {
2949
+ Logger.logError(e, "_waitForCalculationIdToFinish", "Failed to wait for active calculation id change.");
2950
+ return false;
2951
+ }
2952
+ }
2953
+ }
2954
+
2955
+ // TODO: [refactoring, low] Consider removing this logic task_id=c360f2af75764bde8badd9ff1cc00d48
2956
+ class ConcurrentCalculationsMetadataHolder {
2957
+ constructor() {
2958
+ this._calculations = {};
2959
+ }
2960
+ startCalculation(domain, calculationsHistoryMaxLength = 100) {
2961
+ if (!this._calculations[domain]) {
2962
+ this._calculations[domain] = [];
2963
+ }
2964
+ if (this._calculations[domain].length > calculationsHistoryMaxLength) {
2965
+ this._calculations[domain] = this._calculations[domain].slice(Math.round(calculationsHistoryMaxLength * 0.2));
2966
+ }
2967
+ const newCalculation = {
2968
+ startTimestamp: Date.now(),
2969
+ endTimestamp: null,
2970
+ uuid: v4()
2971
+ };
2972
+ this._calculations[domain].push(newCalculation);
2973
+ return newCalculation.uuid;
2974
+ }
2975
+ endCalculation(domain, uuid, isFailed = false) {
2976
+ try {
2977
+ var _calculation$endTimes, _calculation$startTim, _calculation$uuid;
2978
+ const calculation = this._calculations[domain].find(calculation => (calculation == null ? void 0 : calculation.uuid) === uuid);
2979
+ if (calculation) {
2980
+ calculation.endTimestamp = Date.now();
2981
+ calculation.isFiled = isFailed;
2982
+ }
2983
+ const elapsed = ((((_calculation$endTimes = calculation == null ? void 0 : calculation.endTimestamp) != null ? _calculation$endTimes : 0) - ((_calculation$startTim = calculation == null ? void 0 : calculation.startTimestamp) != null ? _calculation$startTim : 0)) / 1000).toFixed(1);
2984
+ Logger.log("endCalculation", `${elapsed} ms: ${domain}.${((_calculation$uuid = calculation == null ? void 0 : calculation.uuid) != null ? _calculation$uuid : "").slice(0, 7)}`);
2985
+ return calculation;
2986
+ } catch (e) {
2987
+ Logger.logError(e, "endCalculation");
2988
+ }
2989
+ }
2990
+ isCalculationLate(domain, uuid) {
2991
+ const queue = this._calculations[domain];
2992
+ const analysingCalculation = queue.find(item => item.uuid === uuid);
2993
+ return analysingCalculation && !!queue.find(calculation => calculation.endTimestamp != null && calculation.startTimestamp > analysingCalculation.startTimestamp);
2994
+ }
2995
+ printCalculationsWaitingMoreThanSpecifiedSeconds(waitingLastsMs = 2000) {
2996
+ const calculations = Object.keys(this._calculations).map(domain => this._calculations[domain].map(c => _extends({}, c, {
2997
+ domain
2998
+ }))).flat().filter(c => c.endTimestamp === null && Date.now() - c.startTimestamp > waitingLastsMs);
2999
+ Logger.log("printCalculationsWaitingMoreThanSpecifiedSeconds", `Calculations waiting more than ${(waitingLastsMs / 1000).toFixed(1)}s:\n` + calculations.map(c => `${c.domain}.${c.uuid.slice(0, 8)}: ${Date.now() - c.startTimestamp}\n`));
3000
+ }
3001
+ }
3002
+ const concurrentCalculationsMetadataHolder = new ConcurrentCalculationsMetadataHolder();
3003
+
3004
+ class ExternalServicesStatsCollector {
3005
+ constructor() {
3006
+ this.stats = new Map();
3007
+ }
3008
+ externalServiceFailed(serviceUrl, message) {
3009
+ try {
3010
+ const processMessage = (stat, errorMessage) => {
3011
+ var _stat$errors, _errorMessage;
3012
+ const errors = (_stat$errors = stat.errors) != null ? _stat$errors : {};
3013
+ errorMessage = (_errorMessage = errorMessage) != null ? _errorMessage : "";
3014
+ if (errorMessage.match(/.*network.+error.*/i)) {
3015
+ errors["networkError"] = (errors["networkError"] || 0) + 1;
3016
+ } else if (errorMessage.match(/.*timeout.+exceeded.*/i)) {
3017
+ errors["timeoutExceeded"] = (errors["timeoutExceeded"] || 0) + 1;
3018
+ } else if (errors["other"]) {
3019
+ errors["other"].push(message);
3020
+ } else {
3021
+ errors["other"] = [message];
3022
+ }
3023
+ stat.errors = errors;
3024
+ };
3025
+ if (this.stats.has(serviceUrl)) {
3026
+ const stat = this.stats.get(serviceUrl);
3027
+ stat.callsCount += 1;
3028
+ stat.failsCount += 1;
3029
+ processMessage(stat, message);
3030
+ } else {
3031
+ this.stats.set(serviceUrl, {
3032
+ callsCount: 1,
3033
+ failsCount: 1
3034
+ });
3035
+ processMessage(this.stats.get(serviceUrl), message);
3036
+ }
3037
+ } catch (e) {
3038
+ improveAndRethrow(e, "externalServiceFailed");
3039
+ }
3040
+ }
3041
+ externalServiceCalledWithoutError(serviceUrl) {
3042
+ try {
3043
+ if (this.stats.has(serviceUrl)) {
3044
+ const stat = this.stats.get(serviceUrl);
3045
+ stat.callsCount += 1;
3046
+ } else {
3047
+ this.stats.set(serviceUrl, {
3048
+ callsCount: 1,
3049
+ failsCount: 0
3050
+ });
3051
+ }
3052
+ } catch (e) {
3053
+ improveAndRethrow(e, "externalServiceCalledWithoutError");
3054
+ }
3055
+ }
3056
+
3057
+ /**
3058
+ * Returns statistics about external services failures.
3059
+ * Provides how many calls were performed and what the percent of failed calls. Also returns errors stat.
3060
+ *
3061
+ * @return {Array<object>} Array of objects of type { failsPerCent: number, calls: number }
3062
+ * sorted by the highest fails percent desc
3063
+ */
3064
+ getStats() {
3065
+ try {
3066
+ return Array.from(this.stats.keys()).map(key => {
3067
+ var _stat$errors2;
3068
+ const stat = this.stats.get(key);
3069
+ return {
3070
+ url: key,
3071
+ failsPerCent: (stat.failsCount / stat.callsCount * 100).toFixed(2),
3072
+ calls: stat.callsCount,
3073
+ errors: (_stat$errors2 = stat.errors) != null ? _stat$errors2 : []
3074
+ };
3075
+ }).sort((s1, s2) => s1.failsPerCent - s2.failsPerCent);
3076
+ } catch (e) {
3077
+ Logger.logError(e, "getStats");
3078
+ }
3079
+ }
3080
+ }
3081
+
3082
+ /**
3083
+ * TODO: [refactoring, critical] update backend copy of this service. Also there is a task to extract this
3084
+ * service and other related to it stuff to dedicated npm package task_id=b008ee5e4a3f42c08c73831c4bb3db4e
3085
+ *
3086
+ * Template service needed to avoid duplication of the same logic when we need to call
3087
+ * external APIs to retrieve some data. The idea is to use several API providers to retrieve the same data. It helps to
3088
+ * improve the reliability of a data retrieval.
3089
+ */
3090
+ class RobustExternalAPICallerService {
3091
+ static getStats() {
3092
+ this.statsCollector.getStats();
3093
+ }
3094
+
3095
+ /**
3096
+ * @param bio {string} service name for logging
3097
+ * @param providersData {ExternalApiProvider[]} array of providers
3098
+ * @param [logger] {function} function to be used for logging
3099
+ */
3100
+ constructor(bio, providersData, logger = Logger.logError) {
3101
+ providersData.forEach(provider => {
3102
+ if (!provider.endpoint && provider.endpoint !== "" || !provider.httpMethod) {
3103
+ throw new Error(`Wrong format of providers data for: ${JSON.stringify(provider)}`);
3104
+ }
3105
+ });
3106
+
3107
+ // We add niceFactor - just number to order the providers array by. It is helpful to call
3108
+ // less robust APIs only if more robust fails
3109
+ this.providers = providersData;
3110
+ providersData.forEach(provider => provider.resetNiceFactor());
3111
+ this.bio = bio;
3112
+ this._logger = Logger.logError;
3113
+ }
3114
+ /**
3115
+ * Performs data retrieval from external APIs. Tries providers till the data is retrieved.
3116
+ *
3117
+ * @param parametersValues {array} array of values of the parameters for URL query string [and/or body]
3118
+ * @param timeoutMS {number} http timeout to wait for response. If provider has its specific timeout value then it is used
3119
+ * @param [cancelToken] {object|undefined} axios token to force-cancel requests from high-level code
3120
+ * @param [attemptsCount] {number|undefined} number of attempts to be performed
3121
+ * @param [doNotFailForNowData] {boolean|undefined} pass true if you do not want us to throw an error if we retrieved null data from all the providers
3122
+ * @return {Promise<any>} resolving to retrieved data (or array of results if specific provider requires
3123
+ * several requests. NOTE: we flatten nested arrays - results of each separate request done for the specific provider)
3124
+ * @throws Error if requests to all providers are failed
3125
+ */
3126
+ async callExternalAPI(parametersValues = [], timeoutMS = 3500, cancelToken = null, attemptsCount = 1, doNotFailForNowData = false) {
3127
+ var _this = this;
3128
+ let result;
3129
+ const calculationUuid = concurrentCalculationsMetadataHolder.startCalculation(this.bio);
3130
+ try {
3131
+ var _result4, _result5;
3132
+ for (let i = 0; (i < attemptsCount || (_result = result) != null && _result.shouldBeForceRetried) && ((_result2 = result) == null ? void 0 : _result2.data) == null; ++i) {
3133
+ var _result, _result2;
3134
+ /**
3135
+ * We use rpsFactor to improve re-attempting to call the providers if the last attempt resulted with
3136
+ * the fail due to abused RPSes of some (most part of) providers.
3137
+ * The _performCallAttempt in such a case will return increased rpsFactor inside the result object.
3138
+ */
3139
+ const rpsFactor = result ? result.rpsFactor : RobustExternalAPICallerService.defaultRPSFactor;
3140
+ result = null;
3141
+ try {
3142
+ var _result3, _result$errors;
3143
+ if (i === 0 && !((_result3 = result) != null && _result3.shouldBeForceRetried)) {
3144
+ result = await this._performCallAttempt(parametersValues, timeoutMS, cancelToken, rpsFactor, doNotFailForNowData);
3145
+ } else {
3146
+ const maxRps = Math.max(...this.providers.map(provider => {
3147
+ var _provider$getRps;
3148
+ return (_provider$getRps = provider.getRps()) != null ? _provider$getRps : 0;
3149
+ }));
3150
+ const waitingTimeMs = maxRps ? 1000 / (maxRps / rpsFactor) : 0;
3151
+ result = await new Promise((resolve, reject) => {
3152
+ setTimeout(async function () {
3153
+ try {
3154
+ resolve(await _this._performCallAttempt(parametersValues, timeoutMS, cancelToken, rpsFactor, doNotFailForNowData));
3155
+ } catch (e) {
3156
+ reject(e);
3157
+ }
3158
+ }, waitingTimeMs);
3159
+ });
3160
+ }
3161
+ if ((_result$errors = result.errors) != null && _result$errors.length) {
3162
+ const errors = result.errors;
3163
+ this._logger(new Error(`Failed at attempt ${i}. ${errors.length} errors. Messages: ${safeStringify(errors.map(error => error.message))}: ${safeStringify(errors)}.`), `${this.bio}.callExternalAPI`, "", true);
3164
+ }
3165
+ } catch (e) {
3166
+ this._logger(e, `${this.bio}.callExternalAPI`, "Failed to perform external providers calling");
3167
+ }
3168
+ }
3169
+ if (((_result4 = result) == null ? void 0 : _result4.data) == null) {
3170
+ // TODO: [feature, moderate] looks like we should not fail for null data as it is strange - the provider will fail when processing data internally
3171
+ const error = new Error(`Failed to retrieve data. It means all attempts have been failed. DEV: add more attempts to this data retrieval`);
3172
+ if (!doNotFailForNowData) {
3173
+ throw error;
3174
+ } else {
3175
+ this._logger(error, `${this.bio}.callExternalAPI`);
3176
+ }
3177
+ }
3178
+ return (_result5 = result) == null ? void 0 : _result5.data;
3179
+ } catch (e) {
3180
+ improveAndRethrow(e, `${this.bio}.callExternalAPI`);
3181
+ } finally {
3182
+ concurrentCalculationsMetadataHolder.endCalculation(this.bio, calculationUuid);
3183
+ }
3184
+ }
3185
+ async _performCallAttempt(parametersValues, timeoutMS, cancelToken, rpsFactor, doNotFailForNowData) {
3186
+ var _data;
3187
+ const providers = this._reorderProvidersByNiceFactor();
3188
+ let data = undefined,
3189
+ providerIndex = 0,
3190
+ countOfRequestsDeclinedByRps = 0,
3191
+ errors = [];
3192
+ while (!data && providerIndex < providers.length) {
3193
+ let provider = providers[providerIndex];
3194
+ if (provider.isRpsExceeded()) {
3195
+ /**
3196
+ * Current provider's RPS is exceeded, so we try next provider. Also, we count such cases to make
3197
+ * a decision about the force-retry need.
3198
+ */
3199
+ ++providerIndex;
3200
+ ++countOfRequestsDeclinedByRps;
3201
+ continue;
3202
+ }
3203
+ try {
3204
+ var _provider$specificHea;
3205
+ const axiosConfig = _extends({}, cancelToken ? {
3206
+ cancelToken
3207
+ } : {}, {
3208
+ timeout: provider.timeout || timeoutMS,
3209
+ headers: (_provider$specificHea = provider.specificHeaders) != null ? _provider$specificHea : {}
3210
+ });
3211
+ const httpMethods = Array.isArray(provider.httpMethod) ? provider.httpMethod : [provider.httpMethod];
3212
+ const iterationsData = [];
3213
+ for (let subRequestIndex = 0; subRequestIndex < httpMethods.length; ++subRequestIndex) {
3214
+ const query = provider.composeQueryString(parametersValues, subRequestIndex);
3215
+ const endpoint = `${provider.endpoint}${query}`;
3216
+ const axiosParams = [endpoint, axiosConfig];
3217
+ if (["post", "put", "patch"].find(method => method === httpMethods[subRequestIndex])) {
3218
+ var _provider$composeBody;
3219
+ const body = (_provider$composeBody = provider.composeBody(parametersValues, subRequestIndex)) != null ? _provider$composeBody : null;
3220
+ axiosParams.splice(1, 0, body);
3221
+ }
3222
+ let pageNumber = 0;
3223
+ const responsesForPages = [];
3224
+ let hasNextPage = provider.doesSupportPagination();
3225
+ do {
3226
+ if (subRequestIndex === 0 && pageNumber === 0) {
3227
+ provider.actualizeLastCalledTimestamp();
3228
+ responsesForPages[pageNumber] = await AxiosAdapter.call(httpMethods[subRequestIndex], ...axiosParams);
3229
+ RobustExternalAPICallerService.statsCollector.externalServiceCalledWithoutError(provider.getApiGroupId());
3230
+ } else {
3231
+ if (pageNumber > 0) {
3232
+ const actualizedParams = provider.changeQueryParametersForPageNumber(parametersValues, responsesForPages[pageNumber - 1], pageNumber, subRequestIndex);
3233
+ const _query = provider.composeQueryString(actualizedParams, subRequestIndex);
3234
+ axiosParams[0] = `${provider.endpoint}${_query}`;
3235
+ }
3236
+ /**
3237
+ * For second and more request we postpone each request to not exceed RPS
3238
+ * of current provider. We use rpsFactor to dynamically increase the rps to avoid
3239
+ * too frequent calls if we continue failing to retrieve the data due to RPS exceeding.
3240
+ * TODO: [dev] test RPS factor logic (units or integration)
3241
+ */
3242
+
3243
+ const waitingTimeMS = provider.getRps() ? 1000 / (provider.getRps() / rpsFactor) : 0;
3244
+ const postponeUntilRpsExceeded = async function postponeUntilRpsExceeded(recursionLevel = 0) {
3245
+ return await postponeExecution(async function () {
3246
+ const maxCountOfPostponingAttempts = 2;
3247
+ if (provider.isRpsExceeded() && recursionLevel < maxCountOfPostponingAttempts) {
3248
+ return await postponeUntilRpsExceeded(recursionLevel + 1);
3249
+ }
3250
+ provider.actualizeLastCalledTimestamp();
3251
+ return await AxiosAdapter.call(httpMethods[subRequestIndex], ...axiosParams);
3252
+ }, waitingTimeMS);
3253
+ };
3254
+ responsesForPages[pageNumber] = await postponeUntilRpsExceeded();
3255
+ }
3256
+ if (hasNextPage) {
3257
+ hasNextPage = !provider.checkWhetherResponseIsForLastPage(responsesForPages[pageNumber - 1], responsesForPages[pageNumber], pageNumber, subRequestIndex);
3258
+ }
3259
+ pageNumber++;
3260
+ } while (hasNextPage);
3261
+ const responsesDataForPages = responsesForPages.map(response => provider.getDataByResponse(response, parametersValues, subRequestIndex, iterationsData));
3262
+ let allData = responsesDataForPages;
3263
+ if (Array.isArray(responsesDataForPages[0])) {
3264
+ allData = responsesDataForPages.flat();
3265
+ } else if (responsesDataForPages.length === 1) {
3266
+ allData = responsesDataForPages[0];
3267
+ }
3268
+ iterationsData.push(allData);
3269
+ }
3270
+ if (iterationsData.length) {
3271
+ if (httpMethods.length > 1) {
3272
+ data = provider.incorporateIterationsData(iterationsData);
3273
+ } else {
3274
+ data = iterationsData[0];
3275
+ }
3276
+ } else if (!doNotFailForNowData) {
3277
+ RobustExternalAPICallerService.statsCollector.externalServiceFailed(provider.getApiGroupId(), "Response data was null for some reason");
3278
+ punishProvider(provider);
3279
+ }
3280
+ } catch (e) {
3281
+ punishProvider(provider);
3282
+ RobustExternalAPICallerService.statsCollector.externalServiceFailed(provider.getApiGroupId(), e == null ? void 0 : e.message);
3283
+ errors.push(e);
3284
+ } finally {
3285
+ providerIndex++;
3286
+ }
3287
+ }
3288
+
3289
+ // If we are declining more than 50% of providers (by exceeding RPS) then we note that it better to retry the whole process of providers requesting
3290
+ const shouldBeForceRetried = data == null && countOfRequestsDeclinedByRps > Math.floor(providers.length * 0.5);
3291
+ const rpsMultiplier = shouldBeForceRetried ? RobustExternalAPICallerService.rpsMultiplier : 1;
3292
+ return {
3293
+ data: (_data = data) != null ? _data : null,
3294
+ shouldBeForceRetried,
3295
+ rpsFactor: rpsFactor * rpsMultiplier,
3296
+ errors
3297
+ };
3298
+ }
3299
+ _reorderProvidersByNiceFactor() {
3300
+ const providersCopy = [...this.providers];
3301
+ return providersCopy.sort((p1, p2) => p2.niceFactor - p1.niceFactor);
3302
+ }
3303
+ }
3304
+ RobustExternalAPICallerService.statsCollector = new ExternalServicesStatsCollector();
3305
+ RobustExternalAPICallerService.defaultRPSFactor = 1;
3306
+ RobustExternalAPICallerService.rpsMultiplier = 1.05;
3307
+ function punishProvider(provider) {
3308
+ provider.niceFactor = provider.niceFactor - 1;
3309
+ }
3310
+
3311
+ /**
3312
+ * Extended edit of RobustExternalApiCallerService supporting cache and management of concurrent requests
3313
+ * to the same resource.
3314
+ * TODO: [tests, critical] Massively used logic
3315
+ */
3316
+ class CachedRobustExternalApiCallerService {
3317
+ /**
3318
+ * @param bio {string} unique service identifier
3319
+ * @param cache {Cache} cache instance
3320
+ * @param providersData {ExternalApiProvider[]} array of providers
3321
+ * @param [cacheTtlMs=10000] {number} time to live for cache ms
3322
+ * @param [maxCallAttemptsToWaitForAlreadyRunningRequest=50] {number} see details in CacheAndConcurrentRequestsResolver
3323
+ * @param [timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished=3000] {number} see details in CacheAndConcurrentRequestsResolver
3324
+ * @param [removeExpiredCacheAutomatically=true] {boolean} whether to remove cached data automatically when ttl exceeds
3325
+ * @param [mergeCachedAndNewlyRetrievedData=null] {function} function accepting cached data, newly retrieved data and id field name for list items
3326
+ * and merging them. use if needed
3327
+ */
3328
+ constructor(bio, cache, providersData, cacheTtlMs = 10000, removeExpiredCacheAutomatically = true, mergeCachedAndNewlyRetrievedData = null, maxCallAttemptsToWaitForAlreadyRunningRequest = 100, timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished = 1000) {
3329
+ this._provider = new RobustExternalAPICallerService(`cached_${bio}`, providersData, Logger.logError);
3330
+ this._cacheTtlMs = cacheTtlMs;
3331
+ this._cahceAndRequestsResolver = new CacheAndConcurrentRequestsResolver(bio, cache, cacheTtlMs, removeExpiredCacheAutomatically, maxCallAttemptsToWaitForAlreadyRunningRequest, timeoutBetweenAttemptsToCheckWhetherAlreadyRunningRequestFinished);
3332
+ this._cahceIds = [];
3333
+ this._mergeCachedAndNewlyRetrievedData = mergeCachedAndNewlyRetrievedData;
3334
+ }
3335
+
3336
+ /**
3337
+ * Calls the external API or returns data from cache. Just waits if the same data already requested.
3338
+ *
3339
+ * @param parametersValues {array} array of values of the parameters for URL query string [and/or body]
3340
+ * @param timeoutMS {number} http timeout to wait for response. If provider has its specific timeout value then it is used
3341
+ * @param [cancelToken] {object|undefined} axios token to force-cancel requests from high-level code
3342
+ * @param [attemptsCount] {number|undefined} number of attempts to be performed
3343
+ * @param [customHashFunctionForParams] {function|undefined} function without params calculating the hash to be
3344
+ * added to bio of the service to compose a unique parameters-specific cache id
3345
+ * @param [doNotFailForNowData] {boolean|undefined} pass true if you do not want us to throw an error if we retrieved null data from all the providers
3346
+ * @return {Promise<any>} resolving to retrieved data (or array of results if specific provider requires
3347
+ * several requests. NOTE: we flatten nested arrays - results of each separate request done for the specific provider)
3348
+ * @throws Error if requests to all providers are failed
3349
+ */
3350
+ async callExternalAPICached(parametersValues = [], timeoutMS = 3500, cancelToken = null, attemptsCount = 1, customHashFunctionForParams = null, doNotFailForNowData = false) {
3351
+ const loggerSource = `${this._provider.bio}.callExternalAPICached`;
3352
+ let cacheId;
3353
+ let result;
3354
+ try {
3355
+ var _result;
3356
+ cacheId = this._calculateCacheId(parametersValues, customHashFunctionForParams);
3357
+ result = await this._cahceAndRequestsResolver.getCachedOrWaitForCachedOrAcquireLock(cacheId);
3358
+ if (!((_result = result) != null && _result.canStartDataRetrieval)) {
3359
+ var _result2;
3360
+ return (_result2 = result) == null ? void 0 : _result2.cachedData;
3361
+ }
3362
+ let data = await this._provider.callExternalAPI(parametersValues, timeoutMS, cancelToken, attemptsCount, doNotFailForNowData);
3363
+ const canPerformMerge = typeof this._mergeCachedAndNewlyRetrievedData === "function";
3364
+ if (canPerformMerge) {
3365
+ const mostRecentCached = this._cahceAndRequestsResolver.getCached(cacheId);
3366
+ data = this._mergeCachedAndNewlyRetrievedData(mostRecentCached, data, parametersValues);
3367
+ }
3368
+ if (data != null) {
3369
+ var _result3;
3370
+ this._cahceAndRequestsResolver.saveCachedData(cacheId, (_result3 = result) == null ? void 0 : _result3.lockId, data, true, canPerformMerge);
3371
+ this._cahceIds.indexOf(cacheId) < 0 && this._cahceIds.push(cacheId);
3372
+ }
3373
+ return data;
3374
+ } catch (e) {
3375
+ improveAndRethrow(e, loggerSource);
3376
+ } finally {
3377
+ var _result4;
3378
+ this._cahceAndRequestsResolver.releaseLock(cacheId, (_result4 = result) == null ? void 0 : _result4.lockId);
3379
+ }
3380
+ }
3381
+ invalidateCaches() {
3382
+ this._cahceIds.forEach(key => this._cahceAndRequestsResolver.invalidate(key));
3383
+ }
3384
+ actualizeCachedData(params, synchronousCurrentCacheProcessor, customHashFunctionForParams = null, sessionDependent = true, actualizedAtTimestamp) {
3385
+ const cacheId = this._calculateCacheId(params, customHashFunctionForParams);
3386
+ this._cahceAndRequestsResolver.actualizeCachedData(cacheId, synchronousCurrentCacheProcessor, sessionDependent);
3387
+ }
3388
+ markCacheAsExpiredButDontRemove(parametersValues, customHashFunctionForParams) {
3389
+ try {
3390
+ this._cahceAndRequestsResolver.markAsExpiredButDontRemove(this._calculateCacheId(parametersValues, customHashFunctionForParams));
3391
+ } catch (e) {
3392
+ improveAndRethrow(e, "markCacheAsExpiredButDontRemove");
3393
+ }
3394
+ }
3395
+ _calculateCacheId(parametersValues, customHashFunctionForParams = null) {
3396
+ try {
3397
+ const hash = typeof customHashFunctionForParams === "function" ? customHashFunctionForParams(parametersValues) : !parametersValues ? "" : new Hashes.SHA512().hex(safeStringify(parametersValues));
3398
+ return `${this._provider.bio}-${hash}`;
3399
+ } catch (e) {
3400
+ improveAndRethrow(e, this._provider.bio + "_calculateCacheId");
3401
+ }
3402
+ }
3403
+ }
3404
+
3405
+ /**
3406
+ * Utils class needed to perform cancelling of axios request inside some process.
3407
+ * Provides cancel state and axios token for HTTP requests
3408
+ */
3409
+ class CancelProcessing {
3410
+ constructor() {
3411
+ this._cancelToken = axios.CancelToken.source();
3412
+ this._isCanceled = false;
3413
+ }
3414
+ cancel() {
3415
+ this._isCanceled = true;
3416
+ this._cancelToken.cancel();
3417
+ }
3418
+ isCanceled() {
3419
+ return this._isCanceled;
3420
+ }
3421
+ getToken() {
3422
+ return this._cancelToken.token;
3423
+ }
3424
+ static instance() {
3425
+ return new CancelProcessing();
3426
+ }
3427
+ }
3428
+
3429
+ class ExternalApiProvider {
3430
+ /**
3431
+ * Creates an instance of external api provider.
3432
+ *
3433
+ * If you need sub-request then use 'subRequestIndex' to check current request index in functions below.
3434
+ * Also use array for 'httpMethod'.
3435
+ *
3436
+ * If the endpoint of dedicated provider has pagination then you should customize the behavior using
3437
+ * "changeQueryParametersForPageNumber", "checkWhetherResponseIsForLastPage".
3438
+ *
3439
+ * We perform RPS counting all over the App to avoid blocking our clients due to abuses of the providers.
3440
+ *
3441
+ * @param endpoint {string} URL to the provider's endpoint. Note: you can customize it using composeQueryString
3442
+ * @param [httpMethod] {string|string[]} one of "get", "post", "put", "patch", "delete" or an array of these values
3443
+ * for request having sub-requests
3444
+ * @param [timeout] {number} number of milliseconds to wait for the response
3445
+ * @param [apiGroup] {ApiGroup} singleton object containing parameters of API group. Helpful when you use the same
3446
+ * api for different providers to avoid hardcoding RPS inside each provider what can cause mistakes
3447
+ * @param [specificHeaders] {Object} contains specific keys (headers) and values (their content) if needed for this provider
3448
+ * @param [maxPageLength] {number} optional number of items per page if the request supports pagination
3449
+ */
3450
+ constructor(endpoint, httpMethod, timeout, apiGroup, specificHeaders = {}, maxPageLength = Number.MAX_SAFE_INTEGER) {
3451
+ this.endpoint = endpoint;
3452
+ this.httpMethod = httpMethod != null ? httpMethod : "get";
3453
+ // TODO: [refactoring, critical] We have two timeouts for robust data retrieval - here and inside the service method call, need to remain the only
3454
+ this.timeout = timeout != null ? timeout : 10000;
3455
+ // TODO: [refactoring, critical] We need single place for all RPSes as we use them as hardcoded constants now inside different services
3456
+ this.apiGroup = apiGroup;
3457
+ this.maxPageLength = maxPageLength != null ? maxPageLength : Number.MAX_SAFE_INTEGER;
3458
+ this.niceFactor = 1;
3459
+ this.specificHeaders = specificHeaders != null ? specificHeaders : {};
3460
+ }
3461
+ getRps() {
3462
+ var _this$apiGroup$rps;
3463
+ return (_this$apiGroup$rps = this.apiGroup.rps) != null ? _this$apiGroup$rps : 2;
3464
+ }
3465
+ isRpsExceeded() {
3466
+ return this.apiGroup.isRpsExceeded();
3467
+ }
3468
+ actualizeLastCalledTimestamp() {
3469
+ this.apiGroup.actualizeLastCalledTimestamp();
3470
+ }
3471
+ getApiGroupId() {
3472
+ return this.apiGroup.id;
3473
+ }
3474
+
3475
+ /**
3476
+ * Some endpoint can require several sub requests. Example is one request to get confirmed transactions
3477
+ * and another request for unconfirmed transactions. You should override this method to return true for such requests.
3478
+ *
3479
+ * @return {boolean} true if this provider requires several requests to retrieve the data
3480
+ */
3481
+ doesRequireSubRequests() {
3482
+ return false;
3483
+ }
3484
+
3485
+ /**
3486
+ * Some endpoint support pagination. Override this method if so and implement corresponding methods.
3487
+ *
3488
+ * @return {boolean} true if this provider requires several requests to retrieve the data
3489
+ */
3490
+ doesSupportPagination() {
3491
+ return false;
3492
+ }
3493
+
3494
+ /**
3495
+ * Composes a query string to be added to the endpoint of this provider.
3496
+ *
3497
+ * @param params {any[]} params array passed to the RobustExternalAPICallerService
3498
+ * @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
3499
+ * @returns {string} query string to be concatenated with endpoint
3500
+ */
3501
+ composeQueryString(params, subRequestIndex = 0) {
3502
+ return "";
3503
+ }
3504
+
3505
+ /**
3506
+ * Composes a body to be added to the request
3507
+ *
3508
+ * @param params {any[]} params array passed to the RobustExternalAPICallerService
3509
+ * @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
3510
+ * @returns {string}
3511
+ */
3512
+ composeBody(params, subRequestIndex = 0) {
3513
+ return "";
3514
+ }
3515
+
3516
+ /**
3517
+ * Extracts data from the response and returns it
3518
+ *
3519
+ * @param response {Object} HTTP response returned by provider
3520
+ * @param [params] {any[]} params array passed to the RobustExternalAPICallerService
3521
+ * @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
3522
+ * @param iterationsData {any[]} array of data retrieved from previous sub-requests
3523
+ * @returns {any}
3524
+ */
3525
+ getDataByResponse(response, params = [], subRequestIndex = 0, iterationsData = []) {
3526
+ return [];
3527
+ }
3528
+
3529
+ /**
3530
+ * Function changing the query string according to page number and previous response
3531
+ * Only for endpoints supporting pagination
3532
+ *
3533
+ * @param params {any[]} params array passed to the RobustExternalAPICallerService
3534
+ * @param previousResponse {Object} HTTP response returned by provider for previous call (previous page)
3535
+ * @param pageNumber {number} new page number. We count from 0. You need to manually increment with 1 if your
3536
+ * provider counts pages starting with 1
3537
+ * @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
3538
+ * @returns {any[]}
3539
+ */
3540
+ changeQueryParametersForPageNumber(params, previousResponse, pageNumber, subRequestIndex = 0) {
3541
+ return params;
3542
+ }
3543
+
3544
+ /**
3545
+ * Function checking whether the response is for the last page to stop requesting for a next page.
3546
+ * Only for endpoints supporting pagination.
3547
+ *
3548
+ * @param previousResponse {Object} HTTP response returned by provider for previous call (previous page)
3549
+ * @param currentResponse {Object} HTTP response returned by provider for current call (current page, next after the previous)
3550
+ * @param currentPageNumber {number} current page number (for current response)
3551
+ * @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
3552
+ * @returns {boolean}
3553
+ */
3554
+ checkWhetherResponseIsForLastPage(previousResponse, currentResponse, currentPageNumber, subRequestIndex = 0) {
3555
+ return true;
3556
+ }
3557
+
3558
+ /**
3559
+ * Resets the nice factor to default value
3560
+ */
3561
+ resetNiceFactor() {
3562
+ this.niceFactor = 1;
3563
+ }
3564
+
3565
+ /**
3566
+ * Internal method used for requests requiring sub-requests.
3567
+ *
3568
+ * @param iterationsData {any[]} iterations data retrieved from getDataByResponse called per sub-request.
3569
+ * @return {any} by default flatten the passed iterations data array. Should be redefined if you need another logic.
3570
+ */
3571
+ incorporateIterationsData(iterationsData) {
3572
+ return iterationsData.flat();
3573
+ }
3574
+ }
3575
+
3576
+ /**
3577
+ * Models a group of APIs provided by the same owner and used for different services in our app.
3578
+ * It means we need to mention RPS several times for each usage and also have some holder of last call timestamp per
3579
+ * api group. So this concept allows to use it for exact ExternalApiProvider and make sure that you use the same
3580
+ * RPS value and make decisions on base of the same timestamp of last call to the API group owner.
3581
+ */
3582
+ class ApiGroup {
3583
+ constructor(id, rps, backendProxyIdGenerator = null) {
3584
+ this.id = id;
3585
+ this.rps = rps;
3586
+ this.lastCalledTimestamp = null;
3587
+ this.backendProxyIdGenerator = backendProxyIdGenerator;
3588
+ }
3589
+ isRpsExceeded() {
3590
+ var _this$lastCalledTimes;
3591
+ return ((_this$lastCalledTimes = this.lastCalledTimestamp) != null ? _this$lastCalledTimes : 0) + Math.floor(1000 / this.rps) > Date.now();
3592
+ }
3593
+ actualizeLastCalledTimestamp() {
3594
+ this.lastCalledTimestamp = Date.now();
3595
+ }
3596
+ }
3597
+ const ApiGroups = {
3598
+ /**
3599
+ * Currently we use free version of etherscan provider with 0.2 RPS. But we have API key with 100k requests free
3600
+ * per month. So we can add it if not enough current RPS.
3601
+ */
3602
+ ETHERSCAN: new ApiGroup("etherscan", 0.17),
3603
+ // Actually 0.2 but fails sometime, so we use smaller
3604
+ ALCHEMY: new ApiGroup("alchemy", 0.3, networkKey => `alchemy-${networkKey}`),
3605
+ BLOCKSTREAM: new ApiGroup("blockstream", 0.2),
3606
+ BLOCKCHAIN_INFO: new ApiGroup("blockchain.info", 1),
3607
+ BLOCKNATIVE: new ApiGroup("blocknative", 0.5),
3608
+ ETHGASSTATION: new ApiGroup("ethgasstation", 0.5),
3609
+ TRONGRID: new ApiGroup("trongrid", 0.3, networkKey => `trongrid-${networkKey}`),
3610
+ TRONSCAN: new ApiGroup("tronscan", 0.3),
3611
+ GETBLOCK: new ApiGroup("getblock", 0.3),
3612
+ COINCAP: new ApiGroup("coincap", 0.5),
3613
+ // 200 per minute without API key
3614
+ COINGECKO: new ApiGroup("coingecko", 0.9),
3615
+ // actually 0.13-0.5 according to the docs but we use smaller due to expirienced frequent abuses
3616
+ MESSARI: new ApiGroup("messari", 0.2),
3617
+ BTCCOM: new ApiGroup("btccom", 0.2),
3618
+ BITAPS: new ApiGroup("bitaps", 0.25),
3619
+ // Docs say that RPS is 3 but using it causes frequent 429 HTTP errors
3620
+ CEX: new ApiGroup("cex", 0.5),
3621
+ // Just assumption for RPS
3622
+ BIGDATACLOUD: new ApiGroup("bigdatacloud", 1),
3623
+ // Just assumption for RPS
3624
+ TRACKIP: new ApiGroup("trackip", 1),
3625
+ // Just assumption for RPS
3626
+ IPIFY: new ApiGroup("ipify", 1),
3627
+ // Just assumption for RPS
3628
+ WHATISMYIPADDRESS: new ApiGroup("whatismyipaddress", 1),
3629
+ // Just assumption for RPS
3630
+ EXCHANGERATE: new ApiGroup("exchangerate", 1),
3631
+ // Just assumption for RPS
3632
+ FRANKFURTER: new ApiGroup("frankfurter", 1),
3633
+ // Just assumption for RPS
3634
+ BITGO: new ApiGroup("bitgo", 1),
3635
+ // Just assumption for RPS
3636
+ BITCOINER: new ApiGroup("bitcoiner", 1),
3637
+ // Just assumption for RPS
3638
+ BITCORE: new ApiGroup("bitcore", 1),
3639
+ // Just assumption for RPS
3640
+ // BLOCKCHAIR: new ApiGroup("blockchair", 0.04), // this provider require API key for commercial use (10usd 10000 reqs), we will add it later
3641
+ MEMPOOL: new ApiGroup("mempool", 0.2) // Just assumption for RPS
3642
+ };
3643
+
3644
+ class ExistingSwap {
3645
+ /**
3646
+ * @param swapId {string}
3647
+ * @param status {SwapProvider.SWAP_STATUSES}
3648
+ * @param createdAt {number}
3649
+ * @param expiresAt {number}
3650
+ * @param confirmations {number}
3651
+ * @param rate {string}
3652
+ * @param refundAddress {string}
3653
+ * @param payToAddress {string}
3654
+ * @param fromCoin {Coin}
3655
+ * @param fromAmount {string}
3656
+ * @param fromTransactionId {string}
3657
+ * @param fromTransactionLink {string}
3658
+ * @param toCoin {Coin}
3659
+ * @param toAmount {string}
3660
+ * @param toTransactionId {string|null}
3661
+ * @param toTransactionLink {string}
3662
+ * @param toAddress {string}
3663
+ * @param partner {string}
3664
+ * @param fromExtraId {string}
3665
+ * @param toExtraId {string}
3666
+ * @param refundExtraId {string}
3667
+ */
3668
+ constructor(swapId, status, createdAt, expiresAt, confirmations, rate, refundAddress, payToAddress, fromCoin, fromAmount, fromTransactionId, fromTransactionLink, toCoin, toAmount, toTransactionId, toTransactionLink, toAddress,
3669
+ // TODO: [refactoring, moderate] toAddress is not quite clear. How about recipientAddress? task_id=0815a111c99543b78d374217eadbde4f
3670
+ partner, fromExtraId, toExtraId, refundExtraId) {
3671
+ this.swapId = swapId;
3672
+ this.status = status;
3673
+ this.createdAt = createdAt;
3674
+ this.expiresAt = expiresAt;
3675
+ this.confirmations = confirmations;
3676
+ this.rate = rate;
3677
+ this.refundAddress = refundAddress;
3678
+ this.payToAddress = payToAddress;
3679
+ this.fromCoin = fromCoin;
3680
+ this.fromTransactionId = fromTransactionId;
3681
+ this.fromAmount = fromAmount;
3682
+ this.fromTransactionLink = fromTransactionLink;
3683
+ this.toCoin = toCoin;
3684
+ this.toTransactionId = toTransactionId;
3685
+ this.toTransactionLink = toTransactionLink;
3686
+ this.toAmount = toAmount;
3687
+ this.toAddress = toAddress;
3688
+ this.partner = partner;
3689
+ this.fromExtraId = fromExtraId;
3690
+ this.toExtraId = toExtraId;
3691
+ this.refundExtraId = refundExtraId;
3692
+ }
3693
+ }
3694
+
3695
+ class ExistingSwapWithFiatData extends ExistingSwap {
3696
+ /**
3697
+ * @param swapId {string}
3698
+ * @param status {SwapProvider.SWAP_STATUSES}
3699
+ * @param createdAt {number}
3700
+ * @param expiresAt {number}
3701
+ * @param confirmations {number}
3702
+ * @param rate {string}
3703
+ * @param refundAddress {string}
3704
+ * @param payToAddress {string}
3705
+ * @param fromCoin {Coin}
3706
+ * @param fromAmount {string}
3707
+ * @param fromTransactionId {string}
3708
+ * @param fromTransactionLink {string}
3709
+ * @param toCoin {Coin}
3710
+ * @param toAmount {string}
3711
+ * @param toTransactionId {string|null}
3712
+ * @param toTransactionLink
3713
+ * @param toAddress {string}
3714
+ * @param partner {string}
3715
+ * @param fromExtraId {string}
3716
+ * @param toExtraId {string}
3717
+ * @param refundExtraId {string}
3718
+ * @param fromAmountFiat {number}
3719
+ * @param toAmountFiat {number}
3720
+ * @param fiatCurrencyCode {string}
3721
+ * @param fiatCurrencyDecimals {number}
3722
+ */
3723
+ constructor(swapId, status, createdAt, expiresAt, confirmations, rate, refundAddress, payToAddress, fromCoin, fromAmount, fromTransactionId, fromTransactionLink, toCoin, toAmount, toTransactionId, toTransactionLink, toAddress, partner, fromExtraId, toExtraId, refundExtraId, fromAmountFiat, toAmountFiat, fiatCurrencyCode, fiatCurrencyDecimals) {
3724
+ super(swapId, status, createdAt, expiresAt, confirmations, rate, refundAddress, payToAddress, fromCoin, fromAmount, fromTransactionId, fromTransactionLink, toCoin, toAmount, toTransactionId, toTransactionLink, toAddress, partner, fromExtraId, toExtraId, refundExtraId);
3725
+ this.fromAmountFiat = fromAmountFiat;
3726
+ this.toAmountFiat = toAmountFiat;
3727
+ this.fiatCurrencyCode = fiatCurrencyCode;
3728
+ this.fiatCurrencyDecimals = fiatCurrencyDecimals;
3729
+ }
3730
+
3731
+ /**
3732
+ * @param existingSwap {ExistingSwap}
3733
+ * @param fromAmountFiat {number}
3734
+ * @param toAmountFiat {number}
3735
+ * @param fiatCurrencyCode {string}
3736
+ * @param fiatCurrencyDecimals {number}
3737
+ * @return {ExistingSwapWithFiatData}
3738
+ */
3739
+ static fromExistingSwap(existingSwap, fromAmountFiat, toAmountFiat, fiatCurrencyCode, fiatCurrencyDecimals) {
3740
+ return new ExistingSwapWithFiatData(existingSwap.swapId, existingSwap.status, existingSwap.createdAt, existingSwap.expiresAt, existingSwap.confirmations, existingSwap.rate, existingSwap.refundAddress, existingSwap.payToAddress, existingSwap.fromCoin, existingSwap.fromAmount, existingSwap.fromTransactionId, existingSwap.fromTransactionLink, existingSwap.toCoin, existingSwap.toAmount, existingSwap.toTransactionId, existingSwap.toTransactionLink, existingSwap.toAddress, existingSwap.partner, existingSwap.fromExtraId, existingSwap.toExtraId, existingSwap.refundExtraId, fromAmountFiat, toAmountFiat, fiatCurrencyCode, fiatCurrencyDecimals);
3741
+ }
3742
+ }
3743
+
3744
+ class BaseSwapCreationInfo {
3745
+ /**
3746
+ * @param fromCoin {Coin}
3747
+ * @param toCoin {Coin}
3748
+ * @param fromAmountCoins {string}
3749
+ * @param toAmountCoins {string}
3750
+ * @param rate {string}
3751
+ * @param rawSwapData {Object}
3752
+ * @param min {string}
3753
+ * @param fiatMin {number}
3754
+ * @param max {string}
3755
+ * @param fiatMax {number}
3756
+ * @param durationMinutesRange {string}
3757
+ */
3758
+ constructor(fromCoin, toCoin, fromAmountCoins, toAmountCoins, rate, rawSwapData, min, fiatMin, max, fiatMax, durationMinutesRange) {
3759
+ this.fromCoin = fromCoin;
3760
+ this.toCoin = toCoin;
3761
+ this.fromAmountCoins = fromAmountCoins;
3762
+ this.toAmountCoins = toAmountCoins;
3763
+ this.rate = rate;
3764
+ this.rawSwapData = rawSwapData;
3765
+ this.min = min;
3766
+ this.fiatMin = fiatMin;
3767
+ this.max = max;
3768
+ this.fiatMax = fiatMax;
3769
+ this.durationMinutesRange = durationMinutesRange;
3770
+ }
3771
+ }
3772
+
3773
+ class SwapProvider {
3774
+ /**
3775
+ * @return {Promise<void>}
3776
+ */
3777
+ async initialize() {
3778
+ throw new Error("Not implemented in base");
3779
+ }
3780
+
3781
+ /**
3782
+ * @return {number} milliseconds TTL
3783
+ */
3784
+ getSwapCreationInfoTtlMs() {
3785
+ throw new Error("Not implemented in base");
3786
+ }
3787
+
3788
+ /**
3789
+ * Retrieves all currencies supported by this swap provider.
3790
+ * Returns one of SwapProvider.COMMON_ERRORS in case of processable fail.
3791
+ *
3792
+ * @return {Promise<({ result: true, coins: Coin[] }|{ result: false, reason: string })>}
3793
+ */
3794
+ async getAllSupportedCurrencies() {
3795
+ throw new Error("Not implemented in base");
3796
+ }
3797
+
3798
+ /**
3799
+ * Retrieves all deposit currencies supported by this swap provider.
3800
+ * Returns one of SwapProvider.COMMON_ERRORS in case of processable fail.
3801
+ *
3802
+ * @return {Promise<({ result: true, coins: Coin[] }|{ result: false, reason: string })>}
3803
+ */
3804
+ async getDepositCurrencies() {
3805
+ throw new Error("Not implemented in base");
3806
+ }
3807
+
3808
+ /**
3809
+ * Retrieves all withdrawable currencies supported by this swap provider.
3810
+ * Returns one of SwapProvider.COMMON_ERRORS in case of processable fail.
3811
+ *
3812
+ * @param [exceptCurrency=null] {Coin|null}
3813
+ * @return {Promise<({ result: true, coins: Coin[] }|{ result: false, reason: string })>}
3814
+ */
3815
+ async getWithdrawalCurrencies(exceptCurrency = null) {
3816
+ throw new Error("Not implemented in base");
3817
+ }
3818
+
3819
+ /**
3820
+ * Retrieves URL for coin icon or fallback if not found.
3821
+ *
3822
+ * @param coin {Coin|string} coin or rabbit-format of coin ticker
3823
+ * @return {string}
3824
+ */
3825
+ getIconUrl(coin) {
3826
+ throw new Error("Not implemented in base");
3827
+ }
3828
+
3829
+ /**
3830
+ * Retrieves coin to USDT rate.
3831
+ *
3832
+ * @param coin {Coin}
3833
+ * @return {{result: true, rate: string}|{result: false}}
3834
+ */
3835
+ async getCoinToUSDTRate(coin) {
3836
+ throw new Error("Not implemented in base");
3837
+ }
3838
+
3839
+ /**
3840
+ * Retrieves estimation for swapping giving coins amount.
3841
+ * null min or max signals there is no corresponding limitation. undefined means that the limits were not retrieved.
3842
+ * For fail result on of SwapProvider.NO_SWAPS_REASONS or SwapProvider.COMMON_ERRORS reasons will be returned.
3843
+ *
3844
+ * WARNING: MUST return NOT_SUPPORTED error code for any case when pair is not available/supported (Should not throw random errors for this case)
3845
+ * @param fromCoin {Coin}
3846
+ * @param toCoin {Coin}
3847
+ * @param amountCoins {string}
3848
+ * @param [fromCoinToUsdRate=null] pass if you want to increase the min amount returned
3849
+ * by provider with some fixed "insurance" amount to cover min amount fluctuations.
3850
+ * @return {Promise<({
3851
+ * result: false,
3852
+ * reason: string,
3853
+ * smallestMin: (string|null|undefined),
3854
+ * greatestMax: (string|null|undefined),
3855
+ * }|{
3856
+ * result: true,
3857
+ * min: (string|null),
3858
+ * max: (string|null),
3859
+ * smallestMin: (string|null),
3860
+ * greatestMax: (string|null),
3861
+ * rate: (string|null),
3862
+ * durationMinutesRange: string,
3863
+ * [rawSwapData]: Object
3864
+ * })>}
3865
+ */
3866
+ async getSwapInfo(fromCoin, toCoin, amountCoins, fromCoinToUsdRate = null) {
3867
+ throw new Error("Not implemented in base");
3868
+ }
3869
+
3870
+ /**
3871
+ * For fail result we return one of SwapProvider.CREATION_FAIL_REASONS or SwapProvider.COMMON_ERRORS.
3872
+ *
3873
+ * @param fromCoin {Coin}
3874
+ * @param toCoin {Coin}
3875
+ * @param amount {string}
3876
+ * @param toAddress {string}
3877
+ * @param refundAddress {string}
3878
+ * @param rawSwapData {Object|null}
3879
+ * @param clientIpAddress {string}
3880
+ * @param [toCurrencyExtraId=""] {string} optional extra ID
3881
+ * @param [refundExtraId=""] {string} optional extra ID for refund address
3882
+ * @return {Promise<({
3883
+ * result: true,
3884
+ * swapId: string,
3885
+ * fromCoin: Coin,
3886
+ * fromAmount: string,
3887
+ * fromAddress: string,
3888
+ * toCoin: Coin,
3889
+ * toAmount: string,
3890
+ * toAddress: string,
3891
+ * rate: string,
3892
+ * fromCurrencyExtraId: string|undefined
3893
+ * }|{
3894
+ * result: false,
3895
+ * reason: string,
3896
+ * partner: string
3897
+ * })>}
3898
+ */
3899
+ async createSwap(fromCoin, toCoin, amount, toAddress, refundAddress, rawSwapData = null, clientIpAddress, toCurrencyExtraId = "", refundExtraId = "") {
3900
+ throw new Error("Not implemented in base");
3901
+ }
3902
+
3903
+ /**
3904
+ * Retrieves details and status for swaps by given ids.
3905
+ * If some swap is not found by id then there is no item in return list.
3906
+ *
3907
+ * @param swapIds {string[]}
3908
+ * @return {Promise<{result: false, reason: string}|{result:true, swaps: ExistingSwap[]}>}
3909
+ */
3910
+ async getExistingSwapsDetailsAndStatus(swapIds) {
3911
+ throw new Error("Not implemented in base");
3912
+ }
3913
+
3914
+ /**
3915
+ * @param ticker {string}
3916
+ * @return {Coin|null}
3917
+ */
3918
+ getCoinByTickerIfPresent(ticker) {
3919
+ throw new Error("Not implemented in base");
3920
+ }
3921
+
3922
+ /**
3923
+ * @param asset {Coin}
3924
+ * @param address {string}
3925
+ * @return {boolean}
3926
+ */
3927
+ isAddressValidForAsset(asset, address) {
3928
+ throw new Error("Not implemented in base");
3929
+ }
3930
+
3931
+ /**
3932
+ * @param asset {Coin}
3933
+ * @return {string|null}
3934
+ */
3935
+ getExtraIdNameIfPresent(asset) {
3936
+ throw new Error("Not implemented in base");
3937
+ }
3938
+ }
3939
+ SwapProvider.COMMON_ERRORS = {
3940
+ REQUESTS_LIMIT_EXCEEDED: "requestsLimitExceeded"
3941
+ };
3942
+ SwapProvider.NO_SWAPS_REASONS = {
3943
+ TOO_LOW: "tooLow",
3944
+ TOO_HIGH: "tooHigh",
3945
+ NOT_SUPPORTED: "notSupported"
3946
+ };
3947
+ SwapProvider.CREATION_FAIL_REASONS = {
3948
+ RETRIABLE_FAIL: "retriableFail"
3949
+ };
3950
+ SwapProvider.SWAP_STATUSES = {
3951
+ WAITING_FOR_PAYMENT: "waiting_for_payment",
3952
+ // public +
3953
+ CONFIRMING: "confirming",
3954
+ PAYMENT_RECEIVED: "payment_received",
3955
+ // public +
3956
+ EXCHANGING: "exchanging",
3957
+ // session full // public +
3958
+ COMPLETED: "completed",
3959
+ // session full // public +
3960
+ REFUNDED: "refunded",
3961
+ // session full // public +
3962
+ EXPIRED: "expired",
3963
+ // public +
3964
+ FAILED: "failed" // public +
3965
+ };
3966
+
3967
+ const BANNED_PARTNERS = ["stealthex", "changee", "coincraddle"];
3968
+ const FALLBACK_ICON_URL = "https://rabbit.io/asset-icons/fallback.svg";
3969
+ class SwapspaceSwapProvider extends SwapProvider {
3970
+ constructor(apiKeysProxyUrl, cache, customCoinBuilder = (coin, network) => null, useRestrictedCoinsSet = true) {
3971
+ super();
3972
+ this._supportedCoins = [];
3973
+ this._URL = `${apiKeysProxyUrl}`;
3974
+ this._maxRateDigits = 20;
3975
+ this.useRestrictedCoinsSet = useRestrictedCoinsSet;
3976
+ this._customCoinBuilder = customCoinBuilder;
3977
+ this._cache = cache;
3978
+ }
3979
+ getSwapCreationInfoTtlMs() {
3980
+ /* Actually 2 minutes and only relevant for some partners, but we use it
3981
+ * (and even a bit smaller value) for better consistency */
3982
+ return 110000;
3983
+ }
3984
+ async getDepositCurrencies() {
3985
+ const loggerSource = "getDepositCurrencies";
3986
+ try {
3987
+ var _this$_supportedCoins;
3988
+ await this._fetchSupportedCurrenciesIfNeeded();
3989
+ Logger.log(`We have ${(_this$_supportedCoins = this._supportedCoins) == null ? void 0 : _this$_supportedCoins.length} supported coins, getting depositable`, loggerSource);
3990
+ return {
3991
+ result: true,
3992
+ coins: this._supportedCoins.filter(item => item.deposit).map(item => item.coin)
3993
+ };
3994
+ } catch (e) {
3995
+ var _e$response;
3996
+ if ((e == null || (_e$response = e.response) == null ? void 0 : _e$response.status) === 429) {
3997
+ return {
3998
+ result: false,
3999
+ reason: SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4000
+ };
4001
+ }
4002
+ improveAndRethrow(e, loggerSource);
4003
+ }
4004
+ }
4005
+ async getAllSupportedCurrencies() {
4006
+ const loggerSource = "getAllSupportedCurrencies";
4007
+ try {
4008
+ var _this$_supportedCoins2;
4009
+ await this._fetchSupportedCurrenciesIfNeeded();
4010
+ Logger.log(`We have ${(_this$_supportedCoins2 = this._supportedCoins) == null ? void 0 : _this$_supportedCoins2.length} supported coins returning`, loggerSource);
4011
+ return {
4012
+ result: true,
4013
+ coins: this._supportedCoins.map(item => item.coin)
4014
+ };
4015
+ } catch (e) {
4016
+ var _e$response2;
4017
+ if ((e == null || (_e$response2 = e.response) == null ? void 0 : _e$response2.status) === 429) {
4018
+ return {
4019
+ result: false,
4020
+ reason: SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4021
+ };
4022
+ }
4023
+ improveAndRethrow(e, loggerSource);
4024
+ }
4025
+ }
4026
+ async getWithdrawalCurrencies(exceptCurrency = null) {
4027
+ const loggerSource = "getWithdrawalCurrencies";
4028
+ try {
4029
+ var _this$_supportedCoins3;
4030
+ await this._fetchSupportedCurrenciesIfNeeded();
4031
+ Logger.log(`We have ${(_this$_supportedCoins3 = this._supportedCoins) == null ? void 0 : _this$_supportedCoins3.length} supported coins, getting withdrawable`, loggerSource);
4032
+ return {
4033
+ result: true,
4034
+ coins: this._supportedCoins.filter(item => {
4035
+ var _item$coin;
4036
+ return item.withdrawal && (!exceptCurrency || ((_item$coin = item.coin) == null ? void 0 : _item$coin.ticker) !== (exceptCurrency == null ? void 0 : exceptCurrency.ticker));
4037
+ }).map(item => item.coin)
4038
+ };
4039
+ } catch (e) {
4040
+ var _e$response3;
4041
+ if ((e == null || (_e$response3 = e.response) == null ? void 0 : _e$response3.status) === 429) {
4042
+ return {
4043
+ result: false,
4044
+ reason: SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4045
+ };
4046
+ }
4047
+ improveAndRethrow(e, loggerSource);
4048
+ }
4049
+ }
4050
+ async initialize() {
4051
+ await this._fetchSupportedCurrenciesIfNeeded();
4052
+ }
4053
+ getIconUrl(coinOrTicker) {
4054
+ const loggerSource = "getIconUrl";
4055
+ try {
4056
+ var _this$_supportedCoins5, _this$_supportedCoins6;
4057
+ let coin = coinOrTicker;
4058
+ if (!(coinOrTicker instanceof Coin)) {
4059
+ var _this$_supportedCoins4;
4060
+ coin = (_this$_supportedCoins4 = this._supportedCoins.find(i => i.coin.ticker === coinOrTicker)) == null ? void 0 : _this$_supportedCoins4.coin;
4061
+ }
4062
+ return (_this$_supportedCoins5 = (_this$_supportedCoins6 = this._supportedCoins.find(item => {
4063
+ var _item$coin2, _coin;
4064
+ return ((_item$coin2 = item.coin) == null ? void 0 : _item$coin2.ticker) === ((_coin = coin) == null ? void 0 : _coin.ticker);
4065
+ })) == null ? void 0 : _this$_supportedCoins6.iconURL) != null ? _this$_supportedCoins5 : FALLBACK_ICON_URL;
4066
+ } catch (e) {
4067
+ improveAndRethrow(e, loggerSource);
4068
+ }
4069
+ }
4070
+ async _fetchSupportedCurrenciesIfNeeded() {
4071
+ const loggerSource = "_fetchSupportedCurrenciesIfNeeded";
4072
+ try {
4073
+ var _this$_supportedCoins7;
4074
+ if (!((_this$_supportedCoins7 = this._supportedCoins) != null && _this$_supportedCoins7.length)) {
4075
+ var _rawResponse$data, _rawResponse$data2;
4076
+ const rawResponse = await axios.get(`${this._URL}/api/v2/currencies`);
4077
+ Logger.log(`Retrieved ${rawResponse == null || (_rawResponse$data = rawResponse.data) == null ? void 0 : _rawResponse$data.length}`, loggerSource);
4078
+ let allowedCoins = (_rawResponse$data2 = rawResponse == null ? void 0 : rawResponse.data) != null ? _rawResponse$data2 : [];
4079
+ Logger.log(`Allowed cnt ${allowedCoins.length}`, loggerSource);
4080
+ this._supportedCoins = allowedCoins.map(item => {
4081
+ let coin = this._customCoinBuilder(item.code, item.network);
4082
+ if (!coin && !this.useRestrictedCoinsSet) {
4083
+ /** Building coin object for coin that isn't supported OOB in Rabbit.
4084
+ * We are doing this way to be able to use extended coins set for swaps.
4085
+ * These temporary built coins are only for in-swap use, and we omit some usual
4086
+ * coin details here.
4087
+ * Ideally we should add some new abstractions e.g. BaseCoin:
4088
+ * Coin will extend BaseCoin, SwapCoin will extend BaseCoin etc.
4089
+ * But for now it is reasonable to use this simpler approach.
4090
+ */
4091
+ const code = item.code.toUpperCase();
4092
+ const network = item.network.toUpperCase();
4093
+ const ticker = `${code}${code === network ? "" : network}`;
4094
+ const defaultDecimalPlacesForCoinNotSupportedOOB = 8;
4095
+ const defaultMinConfirmationsForCoinNotSupportedOOB = 1;
4096
+ // TODO: [dev] maybe we should recognize standard protocols?
4097
+ coin = new Coin(item.name, ticker, code, defaultDecimalPlacesForCoinNotSupportedOOB, null, "", null, null, defaultMinConfirmationsForCoinNotSupportedOOB, null, [], 60000, null,
4098
+ // We cannot recognize blockchain from swapspace data
4099
+ code !== network ? new Protocol(network) : null, item.contractAddress || null, false);
4100
+ }
4101
+ if (coin) {
4102
+ var _item$deposit, _item$withdrawal, _item$validationRegex;
4103
+ return {
4104
+ coin: coin,
4105
+ code: item.code,
4106
+ network: item.network,
4107
+ hasExtraId: item.hasExtraId,
4108
+ extraIdName: item.extraIdName,
4109
+ isPopular: !!(item != null && item.popular),
4110
+ iconURL: item.icon ? `https://storage.swapspace.co${item.icon}` : FALLBACK_ICON_URL,
4111
+ deposit: (_item$deposit = item.deposit) != null ? _item$deposit : false,
4112
+ withdrawal: (_item$withdrawal = item.withdrawal) != null ? _item$withdrawal : false,
4113
+ validationRegexp: (_item$validationRegex = item.validationRegexp) != null ? _item$validationRegex : null
4114
+ };
4115
+ }
4116
+ return [];
4117
+ }).flat();
4118
+ this._putPopularCoinsFirst();
4119
+ }
4120
+ } catch (e) {
4121
+ improveAndRethrow(e, loggerSource);
4122
+ }
4123
+ }
4124
+
4125
+ /**
4126
+ * This method sort internal list putting popular (as swapspace thinks) coins to the top.
4127
+ * This is just for users of this API if they don't care about the sorting - we just improve a list a bit this way.
4128
+ * @private
4129
+ */
4130
+ _putPopularCoinsFirst() {
4131
+ this._supportedCoins.sort((i1, i2) => {
4132
+ if (i1.isPopular && !i2.isPopular) return -1;
4133
+ if (i2.isPopular && !i1.isPopular) return 1;
4134
+ return i1.coin.ticker > i2.coin.ticker ? 1 : i1.coin.ticker < i2.coin.ticker ? -1 : 0;
4135
+ });
4136
+ }
4137
+ async getCoinToUSDTRate(coin) {
4138
+ const loggerSource = "getCoinToUSDTRate";
4139
+ try {
4140
+ var _this$_supportedCoins8;
4141
+ if (!coin) return null;
4142
+ await this._fetchSupportedCurrenciesIfNeeded();
4143
+
4144
+ // Using USDT TRC20 as usually fee in this network is smaller than ERC20 and this network is widely used for USDT
4145
+ const usdtTrc20 = (_this$_supportedCoins8 = this._supportedCoins.find(i => i.coin.ticker === "USDTTRC20")) == null ? void 0 : _this$_supportedCoins8.coin;
4146
+ if (!usdtTrc20) {
4147
+ return {
4148
+ result: false
4149
+ };
4150
+ }
4151
+ const cached = this._cache.get("swapspace_usdt_rate_" + coin.ticker);
4152
+ if (cached != null) {
4153
+ return {
4154
+ result: true,
4155
+ rate: cached
4156
+ };
4157
+ }
4158
+ Logger.log("Loading USDT->coin rate as not found in cache:", coin == null ? void 0 : coin.ticker);
4159
+ const result = await this.getSwapInfo(usdtTrc20, coin, "5000");
4160
+ if (!result.result) {
4161
+ return {
4162
+ result: false
4163
+ };
4164
+ }
4165
+
4166
+ // This calculation is not precise as we cannot recognize the actual fee and network fee. Just approximate.
4167
+ const standardSwapspaceFeeMultiplier = 1.004; // usually 0.2%
4168
+ const rate = BigNumber(1).div(BigNumber(result.rate).times(standardSwapspaceFeeMultiplier)).toString();
4169
+ this._cache.put("swapspace_usdt_rate_" + coin.ticker, rate, 15 * 60000 // 15 minutes
4170
+ );
4171
+ return {
4172
+ result: true,
4173
+ rate: rate
4174
+ };
4175
+ } catch (e) {
4176
+ improveAndRethrow(e, loggerSource);
4177
+ }
4178
+ }
4179
+ getCoinByTickerIfPresent(ticker) {
4180
+ try {
4181
+ var _item$coin3;
4182
+ const item = this._supportedCoins.find(i => i.coin.ticker === ticker);
4183
+ return (_item$coin3 = item == null ? void 0 : item.coin) != null ? _item$coin3 : null;
4184
+ } catch (e) {
4185
+ improveAndRethrow(e, "getCoinByTickerIfPresent");
4186
+ }
4187
+ }
4188
+ async getSwapInfo(fromCoin, toCoin, amountCoins, fromCoinToUsdRate = null) {
4189
+ const loggerSource = "getSwapInfo";
4190
+ try {
4191
+ var _response$data;
4192
+ if (!(fromCoin instanceof Coin) || !(toCoin instanceof Coin) || typeof amountCoins !== "string" || BigNumber(amountCoins).lt("0")) {
4193
+ throw new Error(`Wrong input params: ${amountCoins} ${fromCoin.ticker} -> ${toCoin.ticker}` + (fromCoin instanceof Coin) + (toCoin instanceof Coin));
4194
+ }
4195
+ const fromCoinSwapspaceDetails = this._supportedCoins.find(i => {
4196
+ var _i$coin;
4197
+ return ((_i$coin = i.coin) == null ? void 0 : _i$coin.ticker) === (fromCoin == null ? void 0 : fromCoin.ticker);
4198
+ });
4199
+ const toCoinSwapspaceDetails = this._supportedCoins.find(i => {
4200
+ var _i$coin2;
4201
+ return ((_i$coin2 = i.coin) == null ? void 0 : _i$coin2.ticker) === (toCoin == null ? void 0 : toCoin.ticker);
4202
+ });
4203
+ if (!fromCoinSwapspaceDetails || !toCoinSwapspaceDetails) {
4204
+ throw new Error("Failed to find swapspace coin details for: " + fromCoin.ticker + " -> " + toCoin.ticker);
4205
+ }
4206
+ if (!fromCoinSwapspaceDetails.deposit || !toCoinSwapspaceDetails.withdrawal) {
4207
+ return {
4208
+ result: false,
4209
+ reason: SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
4210
+ };
4211
+ }
4212
+ /* Here we use not documented parameter 'estimated=false'. This parameter controls whether we want to use
4213
+ * cached rate values stored in swapspace cache. Their support says they store at most for 30 sec.
4214
+ * But we are better off using the most actual rates.
4215
+ */
4216
+ const response = await axios.get(`${this._URL}/api/v2/amounts?fromCurrency=${fromCoinSwapspaceDetails.code}&fromNetwork=${fromCoinSwapspaceDetails.network}&toNetwork=${toCoinSwapspaceDetails.network}&toCurrency=${toCoinSwapspaceDetails.code}&amount=${amountCoins}&float=true&estimated=false`);
4217
+ Logger.log(`Retrieved ${response == null || (_response$data = response.data) == null ? void 0 : _response$data.length} options`, loggerSource);
4218
+ const options = Array.isArray(response.data) ? response.data : [];
4219
+ const exchangesSupportingThePair = options.filter(exchange => (exchange == null ? void 0 : exchange.exists) && !BANNED_PARTNERS.find(bannedPartner => bannedPartner === (exchange == null ? void 0 : exchange.partner)) && (exchange == null ? void 0 : exchange.fixed) === false && (exchange.min === 0 || exchange.max === 0 || exchange.max > exchange.min || (typeof exchange.min !== "number" || typeof exchange.max !== "number") && exchange.toAmount > 0));
4220
+ Logger.log(`${exchangesSupportingThePair == null ? void 0 : exchangesSupportingThePair.length} of them have exist=true`, loggerSource);
4221
+ if (!exchangesSupportingThePair.length) {
4222
+ return {
4223
+ result: false,
4224
+ reason: SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
4225
+ };
4226
+ }
4227
+ const availableExchanges = exchangesSupportingThePair.filter(exchange => typeof (exchange == null ? void 0 : exchange.toAmount) === "number" && exchange.toAmount > 0);
4228
+ Logger.log(`Available (having amountTo): ${safeStringify(availableExchanges)}`, loggerSource);
4229
+ // min=0 or max=0 means there is no limit for the partner
4230
+ let smallestMin = null;
4231
+ if (exchangesSupportingThePair.find(ex => BigNumber(ex.min).isZero()) == null) {
4232
+ smallestMin = exchangesSupportingThePair.reduce((prev, cur) => {
4233
+ if (typeof cur.min === "number" && (prev === null || BigNumber(cur.min).lt(prev))) return BigNumber(cur.min);
4234
+ return prev;
4235
+ }, null);
4236
+ }
4237
+ let greatestMax = null;
4238
+ if (exchangesSupportingThePair.find(ex => BigNumber(ex.max).isZero()) == null) {
4239
+ greatestMax = exchangesSupportingThePair.reduce((prev, cur) => {
4240
+ if (typeof cur.max === "number" && (prev === null || BigNumber(cur.max).gt(prev))) return BigNumber(cur.max);
4241
+ return prev;
4242
+ }, null);
4243
+ }
4244
+ let extraCoinsToFitMinMax = "0";
4245
+ if (typeof fromCoinToUsdRate === "string" && BigNumber(fromCoinToUsdRate).gt("0")) {
4246
+ const extraUsdToFitMinMax = BigNumber("1"); // We correct the limits as the exact limit can fluctuate and cause failed swap creation
4247
+ extraCoinsToFitMinMax = AmountUtils.trim(extraUsdToFitMinMax.div(fromCoinToUsdRate), fromCoin.digits);
4248
+ }
4249
+ if (smallestMin instanceof BigNumber) {
4250
+ smallestMin = AmountUtils.trim(smallestMin.plus(extraCoinsToFitMinMax), fromCoin.digits);
4251
+ }
4252
+ if (greatestMax instanceof BigNumber) {
4253
+ if (greatestMax > extraCoinsToFitMinMax) {
4254
+ greatestMax = AmountUtils.trim(greatestMax.minus(extraCoinsToFitMinMax), fromCoin.digits);
4255
+ } else {
4256
+ greatestMax = "0";
4257
+ }
4258
+ }
4259
+ if (availableExchanges.length) {
4260
+ var _bestOpt$duration;
4261
+ const sorted = availableExchanges.sort((op1, op2) => op2.toAmount - op1.toAmount);
4262
+ const bestOpt = sorted[0];
4263
+ Logger.log(`Returning first option after sorting: ${safeStringify(bestOpt)}`, loggerSource);
4264
+ let max = null;
4265
+ let min = null;
4266
+ if (extraCoinsToFitMinMax != null) {
4267
+ if (typeof bestOpt.max === "number" && bestOpt.max !== 0) {
4268
+ max = BigNumber(bestOpt.max).minus(extraCoinsToFitMinMax);
4269
+ max = AmountUtils.trim(max.lt(0) ? "0" : max, fromCoin.digits);
4270
+ }
4271
+ if (typeof bestOpt.min === "number" && bestOpt.min !== 0) {
4272
+ min = AmountUtils.trim(BigNumber(bestOpt.min).plus(extraCoinsToFitMinMax), fromCoin.digits);
4273
+ }
4274
+ }
4275
+ const rate = bestOpt.toAmount && bestOpt.fromAmount ? BigNumber(bestOpt.toAmount).div(bestOpt.fromAmount) : null;
4276
+ return {
4277
+ result: true,
4278
+ min: min,
4279
+ max: max,
4280
+ smallestMin: smallestMin,
4281
+ greatestMax: greatestMax,
4282
+ rate: rate != null ? AmountUtils.trim(rate, this._maxRateDigits) : null,
4283
+ durationMinutesRange: (_bestOpt$duration = bestOpt.duration) != null ? _bestOpt$duration : null,
4284
+ rawSwapData: bestOpt
4285
+ };
4286
+ }
4287
+ const result = {
4288
+ result: false,
4289
+ reason: smallestMin && BigNumber(amountCoins).lt(smallestMin) ? SwapProvider.NO_SWAPS_REASONS.TOO_LOW : greatestMax && BigNumber(amountCoins).gt(greatestMax) ? SwapProvider.NO_SWAPS_REASONS.TOO_HIGH : SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED,
4290
+ smallestMin: smallestMin,
4291
+ greatestMax: greatestMax
4292
+ };
4293
+ Logger.log(`Returning result ${safeStringify(result)}`, loggerSource);
4294
+ return result;
4295
+ } catch (e) {
4296
+ var _e$response4;
4297
+ if ((e == null || (_e$response4 = e.response) == null ? void 0 : _e$response4.status) === 429) {
4298
+ return {
4299
+ result: false,
4300
+ reason: SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4301
+ };
4302
+ }
4303
+ Logger.log(`Internal swapspace/rabbit error when getting swap options ${safeStringify(e)}`, loggerSource);
4304
+ improveAndRethrow(e, loggerSource);
4305
+ }
4306
+ }
4307
+ async createSwap(fromCoin, toCoin, amount, toAddress, refundAddress, rawSwapData, clientIpAddress, toCurrencyExtraId = "", refundExtraId = "") {
4308
+ const loggerSource = "createSwap";
4309
+ const partner = rawSwapData == null ? void 0 : rawSwapData.partner;
4310
+ try {
4311
+ if (!(fromCoin instanceof Coin) || !(toCoin instanceof Coin) || typeof amount !== "string" || typeof toAddress !== "string" || typeof refundAddress !== "string") {
4312
+ throw new Error(`Invalid input: ${fromCoin} ${toCoin} ${amount} ${toAddress} ${refundAddress}`);
4313
+ }
4314
+ if (typeof partner !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.fromCurrency) !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.fromNetwork) !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.toCurrency) !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.toNetwork) !== "string" || typeof (rawSwapData == null ? void 0 : rawSwapData.id) !== "string" // can be just empty
4315
+ ) {
4316
+ throw new Error(`Invalid raw swap data: ${safeStringify(rawSwapData)}`);
4317
+ }
4318
+ await this._fetchSupportedCurrenciesIfNeeded();
4319
+ const requestData = {
4320
+ partner: partner,
4321
+ fromCurrency: rawSwapData == null ? void 0 : rawSwapData.fromCurrency,
4322
+ fromNetwork: rawSwapData == null ? void 0 : rawSwapData.fromNetwork,
4323
+ toCurrency: rawSwapData == null ? void 0 : rawSwapData.toCurrency,
4324
+ toNetwork: rawSwapData == null ? void 0 : rawSwapData.toNetwork,
4325
+ address: toAddress,
4326
+ amount: amount,
4327
+ fixed: false,
4328
+ extraId: toCurrencyExtraId != null ? toCurrencyExtraId : "",
4329
+ refundExtraId: refundExtraId != null ? refundExtraId : "",
4330
+ // This param is not documented. But the refund is usually manual so this is not critical.
4331
+ rateId: rawSwapData == null ? void 0 : rawSwapData.id,
4332
+ userIp: clientIpAddress,
4333
+ refund: refundAddress
4334
+ };
4335
+ Logger.log(`Sending create request: ${safeStringify(requestData)}`, loggerSource);
4336
+ const response = await axios.post(`${this._URL}/api/v2/exchange`, requestData);
4337
+ const result = response.data;
4338
+ Logger.log(`Creation result ${safeStringify(result)}`, loggerSource);
4339
+ if (result != null && result.id) {
4340
+ var _result$from, _result$from2, _result$to, _result$to2, _result$from4, _result$from5, _result$to4, _result$to5, _result$from$extraId, _result$from6;
4341
+ if (typeof (result == null || (_result$from = result.from) == null ? void 0 : _result$from.amount) !== "number" || typeof (result == null || (_result$from2 = result.from) == null ? void 0 : _result$from2.address) !== "string" || typeof (result == null || (_result$to = result.to) == null ? void 0 : _result$to.amount) !== "number" || typeof (result == null || (_result$to2 = result.to) == null ? void 0 : _result$to2.address) !== "string") throw new Error(`Wrong swap creation result ${result}`);
4342
+ /* We use the returned rate preferably but if the retrieved
4343
+ * rate 0/null/undefined we calculate it manually */
4344
+ let rate = result.rate;
4345
+ if (typeof rate !== "number" || BigNumber(rate).isZero()) {
4346
+ var _result$to3, _result$from3;
4347
+ rate = BigNumber(result == null || (_result$to3 = result.to) == null ? void 0 : _result$to3.amount).div(result == null || (_result$from3 = result.from) == null ? void 0 : _result$from3.amount);
4348
+ } else {
4349
+ rate = BigNumber(rate);
4350
+ }
4351
+ return {
4352
+ result: true,
4353
+ swapId: result == null ? void 0 : result.id,
4354
+ fromCoin: fromCoin,
4355
+ fromAmount: AmountUtils.trim(result == null || (_result$from4 = result.from) == null ? void 0 : _result$from4.amount, fromCoin.digits),
4356
+ fromAddress: result == null || (_result$from5 = result.from) == null ? void 0 : _result$from5.address,
4357
+ toCoin: toCoin,
4358
+ toAmount: AmountUtils.trim(result == null || (_result$to4 = result.to) == null ? void 0 : _result$to4.amount, toCoin.digits),
4359
+ toAddress: result == null || (_result$to5 = result.to) == null ? void 0 : _result$to5.address,
4360
+ fromCurrencyExtraId: (_result$from$extraId = result == null || (_result$from6 = result.from) == null ? void 0 : _result$from6.extraId) != null ? _result$from$extraId : "",
4361
+ rate: AmountUtils.trim(rate, this._maxRateDigits)
4362
+ };
4363
+ }
4364
+ const errorMessage = `Swap creation succeeded but the response is wrong: ${safeStringify(response)}`;
4365
+ Logger.log(errorMessage, loggerSource);
4366
+ throw new Error(errorMessage);
4367
+ } catch (e) {
4368
+ var _e$response5, _e$response6;
4369
+ Logger.logError(e, loggerSource, `Failed to create swap. Error is: ${safeStringify(e)}`);
4370
+ const composeFailResult = reason => ({
4371
+ result: false,
4372
+ reason: reason,
4373
+ partner: partner
4374
+ });
4375
+ const status = e == null || (_e$response5 = e.response) == null ? void 0 : _e$response5.status;
4376
+ const data = e == null || (_e$response6 = e.response) == null ? void 0 : _e$response6.data;
4377
+ if (status === 429) {
4378
+ Logger.log(`Returning fail - RPS limit exceeded ${data}`, loggerSource);
4379
+ return composeFailResult(SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED);
4380
+ }
4381
+ const texts422 = ["Pair cannot be processed by", "Currency not found", "Amount maximum is", "Amount minimum is"];
4382
+ const text403 = "IP address is forbidden";
4383
+ if (typeof data === "string" && (status === 403 && data.includes(text403) || status === 422 && texts422.find(text => data.includes(text)))) {
4384
+ Logger.log(`Returning retriable fail: ${status} - ${data}, ${partner}`, loggerSource);
4385
+ return composeFailResult(SwapProvider.CREATION_FAIL_REASONS.RETRIABLE_FAIL);
4386
+ }
4387
+ Logger.log(`Internal swapspace/rabbit error for ${partner}: ${safeStringify(e)}`, loggerSource);
4388
+ improveAndRethrow(e, loggerSource);
4389
+ }
4390
+ }
4391
+ _mapSwapspaceStatusToRabbitStatus(status, isExpiredByTime) {
4392
+ switch (status) {
4393
+ case "waiting":
4394
+ if (isExpiredByTime) {
4395
+ return SwapProvider.SWAP_STATUSES.EXPIRED;
4396
+ }
4397
+ return SwapProvider.SWAP_STATUSES.WAITING_FOR_PAYMENT;
4398
+ case "confirming":
4399
+ return SwapProvider.SWAP_STATUSES.CONFIRMING;
4400
+ case "exchanging":
4401
+ return SwapProvider.SWAP_STATUSES.EXCHANGING;
4402
+ case "sending":
4403
+ return SwapProvider.SWAP_STATUSES.PAYMENT_RECEIVED;
4404
+ case "finished":
4405
+ return SwapProvider.SWAP_STATUSES.COMPLETED;
4406
+ case "verifying":
4407
+ return SwapProvider.SWAP_STATUSES.EXCHANGING;
4408
+ case "refunded":
4409
+ return SwapProvider.SWAP_STATUSES.REFUNDED;
4410
+ case "expired":
4411
+ return SwapProvider.SWAP_STATUSES.EXPIRED;
4412
+ case "failed":
4413
+ return SwapProvider.SWAP_STATUSES.FAILED;
4414
+ default:
4415
+ throw new Error(`Unknown swapspace status: ${status}`);
4416
+ }
4417
+ }
4418
+ async getExistingSwapsDetailsAndStatus(swapIds) {
4419
+ var _this = this;
4420
+ const loggerSource = "getExistingSwapsDetailsAndStatus";
4421
+ try {
4422
+ if (swapIds.find(id => typeof id !== "string")) {
4423
+ throw new Error("Swap id is not string: " + safeStringify(swapIds));
4424
+ }
4425
+ const getNotFailingOn404 = async function getNotFailingOn404(swapId) {
4426
+ try {
4427
+ return await axios.get(`${_this._URL}/api/v2/exchange/${swapId}`);
4428
+ } catch (error) {
4429
+ var _error$response;
4430
+ if ((error == null || (_error$response = error.response) == null ? void 0 : _error$response.status) === 404) return [];
4431
+ throw error;
4432
+ }
4433
+ };
4434
+ const responses = await Promise.all(swapIds.map(swapId => getNotFailingOn404(swapId)));
4435
+ const wo404 = responses.flat();
4436
+ Logger.log("All swaps RAW: " + JSON.stringify(wo404.map(r => r.data)), loggerSource);
4437
+ const swaps = wo404.map(r => r.data).map((swap, index) => {
4438
+ var _this$_supportedCoins9, _this$_supportedCoins10, _swap$from$extraId, _swap$to$extraId, _swap$refundExtraId;
4439
+ const fromCoin = (_this$_supportedCoins9 = this._supportedCoins.find(i => i.code === swap.from.code && i.network === swap.from.network)) == null ? void 0 : _this$_supportedCoins9.coin;
4440
+ const toCoin = (_this$_supportedCoins10 = this._supportedCoins.find(i => i.code === swap.to.code && i.network === swap.to.network)) == null ? void 0 : _this$_supportedCoins10.coin;
4441
+ if (!fromCoin || !toCoin) {
4442
+ return []; // We skip swaps with not supported coins for now
4443
+ }
4444
+ const toUtcTimestamp = timeStr => Date.parse(timeStr.match(/.+[Zz]$/) ? timeStr : `${timeStr}Z`);
4445
+ const expiresAt = toUtcTimestamp(swap.timestamps.expiresAt);
4446
+ const isExpiredByTime = expiresAt < Date.now();
4447
+ const status = this._mapSwapspaceStatusToRabbitStatus(swap.status, isExpiredByTime);
4448
+ const toDigits = status === SwapProvider.SWAP_STATUSES.REFUNDED ? fromCoin.digits : toCoin.digits;
4449
+ const addressToSendCoinsToSwapspace = swap.from.address;
4450
+ return new ExistingSwap(swapIds[index], status, toUtcTimestamp(swap.timestamps.createdAt), expiresAt, swap.confirmations, AmountUtils.trim(swap.rate, this._maxRateDigits), swap.refundAddress, addressToSendCoinsToSwapspace, fromCoin, AmountUtils.trim(swap.from.amount, fromCoin.digits), swap.from.transactionHash, swap.blockExplorerTransactionUrl.from, toCoin, AmountUtils.trim(swap.to.amount, toDigits), swap.to.transactionHash, swap.blockExplorerTransactionUrl.to, swap.to.address, swap.partner, (_swap$from$extraId = swap.from.extraId) != null ? _swap$from$extraId : null, (_swap$to$extraId = swap.to.extraId) != null ? _swap$to$extraId : null, (_swap$refundExtraId = swap.refundExtraId) != null ? _swap$refundExtraId : null);
4451
+ }).flat();
4452
+ Logger.log(`Swap details result ${safeStringify(swaps)}`, loggerSource);
4453
+ return {
4454
+ result: true,
4455
+ swaps: swaps
4456
+ };
4457
+ } catch (e) {
4458
+ var _e$response7, _e$response8;
4459
+ Logger.logError(e, loggerSource, `Failed to get swap details. Error is: ${safeStringify(e)}`);
4460
+ const composeFailResult = reason => ({
4461
+ result: false,
4462
+ reason: reason
4463
+ });
4464
+ const status = e == null || (_e$response7 = e.response) == null ? void 0 : _e$response7.status;
4465
+ const data = e == null || (_e$response8 = e.response) == null ? void 0 : _e$response8.data;
4466
+ if (status === 429) {
4467
+ Logger.log(`Returning fail - RPS limit exceeded ${data}`, loggerSource);
4468
+ return composeFailResult(SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED);
4469
+ }
4470
+ improveAndRethrow(e, loggerSource);
4471
+ }
4472
+ }
4473
+ isAddressValidForAsset(asset, address) {
4474
+ try {
4475
+ const assetData = this._supportedCoins.find(i => {
4476
+ var _i$coin3;
4477
+ return ((_i$coin3 = i.coin) == null ? void 0 : _i$coin3.ticker) === (asset == null ? void 0 : asset.ticker);
4478
+ });
4479
+ if (assetData) {
4480
+ let corrected = assetData.validationRegexp.trim();
4481
+ corrected = corrected[0] === "/" ? corrected.slice(1) : corrected;
4482
+ corrected = corrected[corrected.length - 1] === "/" ? corrected.slice(0, corrected.length - 1) : corrected;
4483
+ return address.match(corrected) != null;
4484
+ }
4485
+ } catch (e) {
4486
+ Logger.logError(e, "isAddressValidForAsset");
4487
+ }
4488
+ return false;
4489
+ }
4490
+ getExtraIdNameIfPresent(asset) {
4491
+ try {
4492
+ const assetData = this._supportedCoins.find(i => {
4493
+ var _i$coin4;
4494
+ return ((_i$coin4 = i.coin) == null ? void 0 : _i$coin4.ticker) === (asset == null ? void 0 : asset.ticker);
4495
+ });
4496
+ if (assetData != null && assetData.hasExtraId) {
4497
+ if ((assetData == null ? void 0 : assetData.extraIdName) == null || (assetData == null ? void 0 : assetData.extraIdName) === "") {
4498
+ // We return some default name if the extraIdName is empty
4499
+ return "ID";
4500
+ }
4501
+ return assetData == null ? void 0 : assetData.extraIdName;
4502
+ }
4503
+ return null;
4504
+ } catch (e) {
4505
+ improveAndRethrow(e, "getExtraIdNameIfPresent");
4506
+ }
4507
+ }
4508
+ }
4509
+
4510
+ class SwapUtils {
4511
+ /**
4512
+ * Retrieves min and max limits for swapping giving currencies.
4513
+ * Returns also conversion rate if possible with predefined amount logic.
4514
+ * Rate is how many "to" coins does 1 "from" coin contain.
4515
+ *
4516
+ * In case of errors returns one of reasons
4517
+ * - SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED
4518
+ * - one of SwapProvider.COMMON_ERRORS.*
4519
+ *
4520
+ * @param swapProvider {SwapProvider}
4521
+ * @param fromCoin {Coin} enabled coin (to swap amount from)
4522
+ * @param toCoin {Coin}
4523
+ * @param coinToCurrentFiatRate {string|null}
4524
+ * @param fiatCurrencyDecimals {number|null}
4525
+ * @return {Promise<{
4526
+ * result: true,
4527
+ * min: string,
4528
+ * fiatMin: (number|null),
4529
+ * max: string,
4530
+ * fiatMax: (number|null),
4531
+ * rate: (string|null),
4532
+ * }|{
4533
+ * result: false,
4534
+ * reason: string
4535
+ * }>}
4536
+ */
4537
+ static async getInitialSwapData(swapProvider, fromCoin, toCoin, coinToCurrentFiatRate = null, fiatCurrencyDecimals = null) {
4538
+ const loggerSource = "getInitialSwapData";
4539
+ try {
4540
+ /* We use some amount here that should fit at least some of the limits of the swap providers.
4541
+ * So we are going to get some rate to be used as the default for the on-flight calculations before we get
4542
+ * the exact rate (that should be retrieved by getSwapCreationInfo method) for a specific amount.
4543
+ */
4544
+ const defaultAmountUsd = BigNumber("300");
4545
+ const coinUsdRate = await swapProvider.getCoinToUSDTRate(fromCoin);
4546
+ const coinAmountForDefaultUsdAmount = AmountUtils.trim(coinUsdRate.result ? defaultAmountUsd.div(coinUsdRate == null ? void 0 : coinUsdRate.rate) : defaultAmountUsd, fromCoin.digits);
4547
+ Logger.log(`Init: ${coinAmountForDefaultUsdAmount} ${fromCoin.ticker}->${toCoin.ticker}`, loggerSource);
4548
+ const details = await swapProvider.getSwapInfo(fromCoin, toCoin, coinAmountForDefaultUsdAmount);
4549
+ if (!details) {
4550
+ throw new Error("The details are empty: " + safeStringify(details));
4551
+ }
4552
+ if (!details.result) {
4553
+ Logger.log(`Failed with reason: ${details.reason}. ${fromCoin.ticker}->${toCoin.ticker}`, loggerSource);
4554
+ if ((details == null ? void 0 : details.reason) === SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED || (details == null ? void 0 : details.reason) === SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED) {
4555
+ return {
4556
+ result: false,
4557
+ reason: details.reason
4558
+ };
4559
+ } else {
4560
+ throw new Error("Unhandled error case: " + (details == null ? void 0 : details.reason));
4561
+ }
4562
+ }
4563
+ let fiatMin = null;
4564
+ let fiatMax = null;
4565
+ const fiatRate = coinToCurrentFiatRate != null ? coinToCurrentFiatRate : coinUsdRate == null ? void 0 : coinUsdRate.rate;
4566
+ const fiatDecimals = fiatCurrencyDecimals != null ? fiatCurrencyDecimals : FiatCurrenciesService.getCurrencyDecimalCountByCode("USD");
4567
+ if (fiatRate != null) {
4568
+ fiatMin = BigNumber(details == null ? void 0 : details.smallestMin).times(fiatRate).toFixed(fiatDecimals);
4569
+ fiatMax = BigNumber(details == null ? void 0 : details.greatestMax).times(fiatRate).toFixed(fiatDecimals);
4570
+ }
4571
+ const result = {
4572
+ result: true,
4573
+ min: details == null ? void 0 : details.smallestMin,
4574
+ fiatMin: fiatMin,
4575
+ max: details == null ? void 0 : details.greatestMax,
4576
+ fiatMax: fiatMax,
4577
+ rate: AmountUtils.trim(details.rate, 30)
4578
+ };
4579
+ Logger.log(`Returning: ${safeStringify(result)}`, loggerSource);
4580
+ return result;
4581
+ } catch (e) {
4582
+ Logger.logError(e, loggerSource, `Failed to init swap: ${safeStringify(e)}`);
4583
+ improveAndRethrow(e, loggerSource);
4584
+ }
4585
+ }
4586
+ static safeHandleRequestsLimitExceeding() {
4587
+ (async function () {
4588
+ try {
4589
+ await EmailsApi.sendEmail("AUTOMATIC EMAIL - SWAPSPACE REQUESTS LIMIT EXCEEDED", "Requests limit exceeded. Urgently ask swaps provider support for limit increasing");
4590
+ } catch (e) {
4591
+ Logger.log(`Failed to handle limit exceeding ${safeStringify(e)}`, "_safeHandleRequestsLimitExceeding");
4592
+ }
4593
+ })();
4594
+ }
4595
+
4596
+ /**
4597
+ * If some swap is not found by id then there is no item in return list.
4598
+ *
4599
+ * @param swapProvider {SwapProvider}
4600
+ * @param swapIds {string[]}
4601
+ * @return {Promise<{
4602
+ * result: true,
4603
+ * swaps: ExistingSwapWithFiatData[]
4604
+ * }|{
4605
+ * result: false,
4606
+ * reason: string
4607
+ * }>}
4608
+ */
4609
+ static async getExistingSwapsDetailsWithFiatAmounts(swapProvider, swapIds) {
4610
+ try {
4611
+ const result = await swapProvider.getExistingSwapsDetailsAndStatus(swapIds);
4612
+ if (result.result) {
4613
+ const extendedSwaps = [];
4614
+ for (let swap of result.swaps) {
4615
+ if (swap.status === SwapProvider.SWAP_STATUSES.REFUNDED) {
4616
+ const rate = await swapProvider.getCoinToUSDTRate(swap.fromCoin);
4617
+ extendedSwaps.push(ExistingSwapWithFiatData.fromExistingSwap(swap, (rate == null ? void 0 : rate.rate) != null ? BigNumber(swap.fromAmount).times(rate.rate).toNumber() : null, (rate == null ? void 0 : rate.rate) != null ? BigNumber(swap.toAmount).times(rate.rate).toNumber() : null, "USD", FiatCurrenciesService.getCurrencyDecimalCountByCode("USD")));
4618
+ } else {
4619
+ const [fromCoinFiatRate, toConFiatRate] = await Promise.all([swapProvider.getCoinToUSDTRate(swap.fromCoin), swapProvider.getCoinToUSDTRate(swap.toCoin)]);
4620
+ extendedSwaps.push(ExistingSwapWithFiatData.fromExistingSwap(swap, (fromCoinFiatRate == null ? void 0 : fromCoinFiatRate.rate) != null ? BigNumber(swap.fromAmount).times(fromCoinFiatRate.rate).toNumber() : null, (toConFiatRate == null ? void 0 : toConFiatRate.rate) != null ? BigNumber(swap.toAmount).times(toConFiatRate.rate).toNumber() : null, "USD", FiatCurrenciesService.getCurrencyDecimalCountByCode("USD")));
4621
+ }
4622
+ }
4623
+ result.swaps = extendedSwaps;
4624
+ }
4625
+ return result;
4626
+ } catch (e) {
4627
+ improveAndRethrow(e, "getExistingSwapsDetailsWithFiatAmounts");
4628
+ }
4629
+ }
4630
+ }
4631
+
4632
+ class PublicSwapService {
4633
+ constructor(apiKeysProxyUrl, cache) {
4634
+ this._swapProvider = new SwapspaceSwapProvider(apiKeysProxyUrl, cache, () => null, false);
4635
+ }
4636
+ async initialize() {
4637
+ try {
4638
+ await this._swapProvider.initialize();
4639
+ } catch (e) {
4640
+ Logger.logError(e, "PublicSwapService.initialize");
4641
+ }
4642
+ }
4643
+ async getAllSupportedCurrenciesListForPublicSwap() {
4644
+ const loggerSource = "getAllSupportedCurrenciesListForPublicSwap";
4645
+ try {
4646
+ var _result$coins;
4647
+ const result = await this._swapProvider.getAllSupportedCurrencies();
4648
+ if (result.reason === SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED) {
4649
+ SwapUtils.safeHandleRequestsLimitExceeding();
4650
+ return {
4651
+ result: false,
4652
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4653
+ };
4654
+ }
4655
+ Logger.log(`Retrieved ${result == null || (_result$coins = result.coins) == null ? void 0 : _result$coins.length} supported currencies for swap`, loggerSource);
4656
+ return {
4657
+ result: true,
4658
+ coins: result.coins
4659
+ };
4660
+ } catch (e) {
4661
+ improveAndRethrow(e, "getDepositCurrenciesListForPublicSwap");
4662
+ }
4663
+ }
4664
+ async getDepositCurrenciesListForPublicSwap() {
4665
+ try {
4666
+ return await this._getCurrenciesListForPublicSwap(false);
4667
+ } catch (e) {
4668
+ improveAndRethrow(e, "getDepositCurrenciesListForPublicSwap");
4669
+ }
4670
+ }
4671
+ async getWithdrawCurrenciesListForPublicSwap() {
4672
+ try {
4673
+ return await this._getCurrenciesListForPublicSwap(true);
4674
+ } catch (e) {
4675
+ improveAndRethrow(e, "getWithdrawCurrenciesListForPublicSwap");
4676
+ }
4677
+ }
4678
+ async _getCurrenciesListForPublicSwap(withdraw = false) {
4679
+ const loggerSource = "getCurrenciesListForPublicSwap";
4680
+ try {
4681
+ var _result$coins2;
4682
+ const result = withdraw ? await this._swapProvider.getWithdrawalCurrencies() : await this._swapProvider.getDepositCurrencies();
4683
+ if (result.reason === SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED) {
4684
+ SwapUtils.safeHandleRequestsLimitExceeding();
4685
+ return {
4686
+ result: false,
4687
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4688
+ };
4689
+ }
4690
+ Logger.log(`Retrieved ${result == null || (_result$coins2 = result.coins) == null ? void 0 : _result$coins2.length} supported currencies for swap (withdraw=${withdraw})`, loggerSource);
4691
+ return {
4692
+ result: true,
4693
+ coins: result.coins
4694
+ };
4695
+ } catch (e) {
4696
+ improveAndRethrow(e, loggerSource);
4697
+ }
4698
+ }
4699
+
4700
+ /**
4701
+ * Retrieves initial data for swapping two coins.
4702
+ *
4703
+ * @param fromCoin {Coin}
4704
+ * @param toCoin {Coin}
4705
+ * @return {Promise<{
4706
+ * result: true,
4707
+ * min: string,
4708
+ * fiatMin: (number|null),
4709
+ * max: string,
4710
+ * fiatMax: (number|null),
4711
+ * rate: (string|null)
4712
+ * }|{
4713
+ * result: false,
4714
+ * reason: string
4715
+ * }>}
4716
+ */
4717
+ async getInitialPublicSwapData(fromCoin, toCoin) {
4718
+ try {
4719
+ const result = await SwapUtils.getInitialSwapData(this._swapProvider, fromCoin, toCoin);
4720
+ if (!result.result) {
4721
+ if (result.reason === SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED) {
4722
+ SwapUtils.safeHandleRequestsLimitExceeding();
4723
+ return {
4724
+ result: false,
4725
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4726
+ };
4727
+ }
4728
+ if (result.reason === SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED) {
4729
+ return {
4730
+ result: false,
4731
+ reason: PublicSwapService.PUBLIC_SWAP_DETAILS_FAIL_REASONS.PAIR_NOT_SUPPORTED
4732
+ };
4733
+ }
4734
+ }
4735
+ return result;
4736
+ } catch (e) {
4737
+ improveAndRethrow(e, "getInitialPublicSwapData");
4738
+ }
4739
+ }
4740
+
4741
+ /**
4742
+ * Retrieves swap details that can be used to create swap.
4743
+ *
4744
+ * @param fromCoin {Coin}
4745
+ * @param toCoin {Coin}
4746
+ * @param fromAmountCoins {string}
4747
+ * @param [withoutFiat=false] {boolean} pass true if you don't need the fiat equivalent - this will diminish requests count
4748
+ * @return {Promise<{
4749
+ * result: false,
4750
+ * reason: string,
4751
+ * min: (string|null),
4752
+ * max: (string|null),
4753
+ * rate: (string|undefined),
4754
+ * fiatMin: (number|null),
4755
+ * fiatMax: (number|null)
4756
+ * }|{
4757
+ * result: true,
4758
+ * swapCreationInfo: BaseSwapCreationInfo
4759
+ * }>}
4760
+ */
4761
+ async getPublicSwapDetails(fromCoin, toCoin, fromAmountCoins, withoutFiat = false) {
4762
+ const loggerSource = "getPublicSwapDetails";
4763
+ try {
4764
+ var _await$this$_swapProv, _await$this$_swapProv2, _result$swapCreationI, _result$swapCreationI2;
4765
+ const coinUsdtRate = withoutFiat ? null : (_await$this$_swapProv = (_await$this$_swapProv2 = await this._swapProvider.getCoinToUSDTRate(fromCoin)) == null ? void 0 : _await$this$_swapProv2.rate) != null ? _await$this$_swapProv : null;
4766
+ const details = await this._swapProvider.getSwapInfo(fromCoin, toCoin, fromAmountCoins, coinUsdtRate);
4767
+ const min = details.result ? details.min : details.smallestMin;
4768
+ const max = details.result ? details.max : details.greatestMax;
4769
+ let fiatMin = null,
4770
+ fiatMax = null;
4771
+ if (coinUsdtRate != null) {
4772
+ if (min != null) {
4773
+ fiatMin = BigNumber(min).times(coinUsdtRate).toFixed(PublicSwapService._fiatDecimalsCount);
4774
+ }
4775
+ if (max != null) {
4776
+ fiatMax = BigNumber(max).times(coinUsdtRate).toFixed(PublicSwapService._fiatDecimalsCount);
4777
+ }
4778
+ }
4779
+ const composeFailResult = reason => {
4780
+ var _details$rate;
4781
+ return {
4782
+ result: false,
4783
+ reason: reason,
4784
+ min: min != null ? min : null,
4785
+ fiatMin: fiatMin,
4786
+ max: max != null ? max : null,
4787
+ fiatMax: fiatMax,
4788
+ rate: (_details$rate = details.rate) != null ? _details$rate : null
4789
+ };
4790
+ };
4791
+ if (!details.result) {
4792
+ if ((details == null ? void 0 : details.reason) === SwapProvider.NO_SWAPS_REASONS.NOT_SUPPORTED) return composeFailResult(PublicSwapService.PUBLIC_SWAP_DETAILS_FAIL_REASONS.PAIR_NOT_SUPPORTED);else if ((details == null ? void 0 : details.reason) === SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED) {
4793
+ SwapUtils.safeHandleRequestsLimitExceeding();
4794
+ return composeFailResult(PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED);
4795
+ }
4796
+ }
4797
+ const fromAmountBigNumber = BigNumber(fromAmountCoins);
4798
+ if (typeof min === "string" && fromAmountBigNumber.lt(min)) {
4799
+ return composeFailResult(PublicSwapService.PUBLIC_SWAP_DETAILS_FAIL_REASONS.AMOUNT_LESS_THAN_MIN_SWAPPABLE);
4800
+ } else if (typeof max === "string" && fromAmountBigNumber.gt(max)) {
4801
+ return composeFailResult(PublicSwapService.PUBLIC_SWAP_DETAILS_FAIL_REASONS.AMOUNT_HIGHER_THAN_MAX_SWAPPABLE);
4802
+ }
4803
+ const toAmountCoins = AmountUtils.trim(fromAmountBigNumber.times(details.rate), fromCoin.digits);
4804
+ const result = {
4805
+ result: true,
4806
+ swapCreationInfo: new BaseSwapCreationInfo(fromCoin, toCoin, fromAmountCoins, toAmountCoins, details.rate, details.rawSwapData, min, fiatMin, max, fiatMax, details.durationMinutesRange)
4807
+ };
4808
+ Logger.log(`Result: ${safeStringify({
4809
+ result: result.result,
4810
+ swapCreationInfo: _extends({}, result.swapCreationInfo, {
4811
+ fromCoin: result == null || (_result$swapCreationI = result.swapCreationInfo) == null || (_result$swapCreationI = _result$swapCreationI.fromCoin) == null ? void 0 : _result$swapCreationI.ticker,
4812
+ toCoin: result == null || (_result$swapCreationI2 = result.swapCreationInfo) == null || (_result$swapCreationI2 = _result$swapCreationI2.toCoin) == null ? void 0 : _result$swapCreationI2.ticker
4813
+ })
4814
+ })}`, loggerSource);
4815
+ return result;
4816
+ } catch (e) {
4817
+ improveAndRethrow(e, loggerSource);
4818
+ }
4819
+ }
4820
+
4821
+ /**
4822
+ * Creates swap by given params.
4823
+ *
4824
+ * @param fromCoin {Coin}
4825
+ * @param toCoin {Coin}
4826
+ * @param fromAmount {string}
4827
+ * @param swapCreationInfo {BaseSwapCreationInfo}
4828
+ * @param toAddress {string}
4829
+ * @param refundAddress {string}
4830
+ * @param clientIp {string}
4831
+ * @param [toCurrencyExtraId] {string}
4832
+ * @param [refundExtraId] {string}
4833
+ * @return {Promise<{
4834
+ * result: true,
4835
+ * fiatCurrencyCode: string,
4836
+ * toCoin: Coin,
4837
+ * fromAmountFiat: (number|null),
4838
+ * address: string,
4839
+ * durationMinutesRange: string,
4840
+ * fromAmount: string,
4841
+ * toAmount: string,
4842
+ * toAmountFiat: (number|null),
4843
+ * fiatCurrencyDecimals: number,
4844
+ * fromCoin: Coin,
4845
+ * rate: string,
4846
+ * swapId: string,
4847
+ * fromCurrencyExtraId: string
4848
+ * }|{
4849
+ * result: false,
4850
+ * reason: string
4851
+ * }>}
4852
+ */
4853
+ async createPublicSwap(fromCoin, toCoin, fromAmount, swapCreationInfo, toAddress, refundAddress, clientIp, toCurrencyExtraId, refundExtraId) {
4854
+ const loggerSource = "createPublicSwap";
4855
+ try {
4856
+ var _swapCreationInfo$fro, _swapCreationInfo$toC;
4857
+ if (!(fromCoin instanceof Coin) || !(toCoin instanceof Coin) || typeof fromAmount !== "string" || typeof toAddress !== "string" || typeof refundAddress !== "string" || !(swapCreationInfo instanceof BaseSwapCreationInfo)) {
4858
+ throw new Error(`Wrong input: ${fromCoin.ticker} ${toCoin.ticker} ${fromAmount} ${swapCreationInfo}`);
4859
+ }
4860
+ Logger.log(`Start: ${fromAmount} ${fromCoin.ticker} -> ${toCoin.ticker}. Details: ${safeStringify(_extends({}, swapCreationInfo, {
4861
+ fromCoin: swapCreationInfo == null || (_swapCreationInfo$fro = swapCreationInfo.fromCoin) == null ? void 0 : _swapCreationInfo$fro.ticker,
4862
+ toCoin: swapCreationInfo == null || (_swapCreationInfo$toC = swapCreationInfo.toCoin) == null ? void 0 : _swapCreationInfo$toC.ticker
4863
+ }))}`, loggerSource);
4864
+ const result = await this._swapProvider.createSwap(fromCoin, toCoin, fromAmount, toAddress, refundAddress, swapCreationInfo.rawSwapData, clientIp, toCurrencyExtraId, refundExtraId);
4865
+ Logger.log(`Created:${safeStringify(_extends({}, result, {
4866
+ fromCoin: fromCoin == null ? void 0 : fromCoin.ticker,
4867
+ toCoin: toCoin == null ? void 0 : toCoin.ticker
4868
+ }))}`, loggerSource);
4869
+ if (!(result != null && result.result)) {
4870
+ if ((result == null ? void 0 : result.reason) === SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED) {
4871
+ SwapUtils.safeHandleRequestsLimitExceeding();
4872
+ return {
4873
+ result: false,
4874
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4875
+ };
4876
+ }
4877
+ if ((result == null ? void 0 : result.reason) === SwapProvider.CREATION_FAIL_REASONS.RETRIABLE_FAIL) {
4878
+ // TODO: [feature, high] implement retrying if one partner fail and we have another partners task_id=a07e367e488f4a4899613ac9056fa359
4879
+ // return {
4880
+ // result: false,
4881
+ // reason: PublicSwapService.SWAP_CREATION_FAIL_REASONS.RETRIABLE_FAIL,
4882
+ // };
4883
+ }
4884
+ }
4885
+ if (result.result && result != null && result.swapId) {
4886
+ var _result$fromCurrencyE;
4887
+ let fromAmountFiat = null,
4888
+ toAmountFiat = null;
4889
+ try {
4890
+ var _await$this$_swapProv3, _await$this$_swapProv4, _await$this$_swapProv5, _await$this$_swapProv6;
4891
+ const fromCoinUsdtRate = (_await$this$_swapProv3 = (_await$this$_swapProv4 = await this._swapProvider.getCoinToUSDTRate(fromCoin)) == null ? void 0 : _await$this$_swapProv4.rate) != null ? _await$this$_swapProv3 : null;
4892
+ const toCoinUsdtRate = (_await$this$_swapProv5 = (_await$this$_swapProv6 = await this._swapProvider.getCoinToUSDTRate(fromCoin)) == null ? void 0 : _await$this$_swapProv6.rate) != null ? _await$this$_swapProv5 : null;
4893
+ if (fromCoinUsdtRate != null && result.fromAmount != null) {
4894
+ fromAmountFiat = BigNumber(result.fromAmount).times(fromCoinUsdtRate).toFixed(PublicSwapService._fiatDecimalsCount);
4895
+ }
4896
+ if (toCoinUsdtRate != null && result.toAmount != null) {
4897
+ toAmountFiat = BigNumber(result.toAmount).times(toCoinUsdtRate).toFixed(PublicSwapService._fiatDecimalsCount);
4898
+ }
4899
+ } catch (e) {
4900
+ Logger.logError(e, loggerSource, "Failed to calculate fiat amounts for result");
4901
+ }
4902
+ EventBusInstance.dispatch(PublicSwapService.PUBLIC_SWAP_CREATED_EVENT, null, fromCoin.ticker, toCoin.ticker, fromAmountFiat);
4903
+ const toReturn = {
4904
+ result: true,
4905
+ swapId: result.swapId,
4906
+ fromCoin: fromCoin,
4907
+ toCoin: toCoin,
4908
+ fromAmount: result.fromAmount,
4909
+ toAmount: result.toAmount,
4910
+ fromAmountFiat: fromAmountFiat,
4911
+ toAmountFiat: toAmountFiat,
4912
+ fiatCurrencyCode: "USD",
4913
+ fiatCurrencyDecimals: PublicSwapService._fiatDecimalsCount,
4914
+ rate: result.rate,
4915
+ durationMinutesRange: swapCreationInfo.durationMinutesRange,
4916
+ address: result.fromAddress,
4917
+ // CRITICAL: this is the address to send coins to swaps provider
4918
+ fromCurrencyExtraId: (_result$fromCurrencyE = result.fromCurrencyExtraId) != null ? _result$fromCurrencyE : "" // CRITICAL: this is the extra ID for address to send coins to swaps provider
4919
+ };
4920
+ this._savePublicSwapIdLocally(result.swapId);
4921
+ Logger.log(`Returning: ${safeStringify(_extends({}, toReturn, {
4922
+ fromCoin: fromCoin == null ? void 0 : fromCoin.ticker,
4923
+ toCoin: toCoin == null ? void 0 : toCoin.ticker
4924
+ }))}`, loggerSource);
4925
+ return toReturn;
4926
+ }
4927
+ throw new Error(`Unexpected result from provider ${safeStringify(result)}`);
4928
+ } catch (e) {
4929
+ improveAndRethrow(e, loggerSource);
4930
+ }
4931
+ }
4932
+
4933
+ /**
4934
+ * Retrieves swap details and status for existing swaps by their ids.
4935
+ *
4936
+ * @param swapIds {string[]}
4937
+ * @return {Promise<{
4938
+ * result: true,
4939
+ * swaps: ExistingSwapWithFiatData[]
4940
+ * }|{
4941
+ * result: false,
4942
+ * reason: string
4943
+ * }>}
4944
+ * error reason is one of PUBLIC_SWAPS_COMMON_ERRORS
4945
+ */
4946
+ async getPublicExistingSwapDetailsAndStatus(swapIds) {
4947
+ const loggerSource = "getPublicExistingSwapDetailsAndStatus";
4948
+ try {
4949
+ const result = await SwapUtils.getExistingSwapsDetailsWithFiatAmounts(this._swapProvider, swapIds);
4950
+ if (!(result != null && result.result)) {
4951
+ if (result.reason === SwapProvider.COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED) {
4952
+ SwapUtils.safeHandleRequestsLimitExceeding();
4953
+ return {
4954
+ result: false,
4955
+ reason: PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS.REQUESTS_LIMIT_EXCEEDED
4956
+ };
4957
+ }
4958
+ throw new Error("Unknown reason: " + (result == null ? void 0 : result.reason));
4959
+ }
4960
+ return result;
4961
+ } catch (e) {
4962
+ improveAndRethrow(e, loggerSource);
4963
+ }
4964
+ }
4965
+
4966
+ /**
4967
+ * Retrieves the whole available swaps history by ids saved locally.
4968
+ *
4969
+ * @return {Promise<{
4970
+ * result: true,
4971
+ * swaps: ExistingSwapWithFiatData[]
4972
+ * }|{
4973
+ * result: false,
4974
+ * reason: string
4975
+ * }>}
4976
+ */
4977
+ async getPublicSwapsHistory() {
4978
+ try {
4979
+ const swapIds = this._getPublicSwapIdsSavedLocally();
4980
+ if (swapIds.length) {
4981
+ return await this.getPublicExistingSwapDetailsAndStatus(swapIds);
4982
+ }
4983
+ return {
4984
+ result: true,
4985
+ swaps: []
4986
+ };
4987
+ } catch (e) {
4988
+ improveAndRethrow(e, "getPublicSwapsHistory");
4989
+ }
4990
+ }
4991
+
4992
+ /**
4993
+ * @param swapId {string}
4994
+ * @private
4995
+ */
4996
+ _savePublicSwapIdLocally(swapId) {
4997
+ if (typeof window !== "undefined") {
4998
+ try {
4999
+ const saved = localStorage.getItem("publicSwapIds");
5000
+ const ids = typeof saved === "string" && saved.length > 0 ? saved.split(",") : [];
5001
+ ids.push(swapId);
5002
+ localStorage.setItem("publicSwapIds", ids.join(","));
5003
+ } catch (e) {
5004
+ improveAndRethrow(e, "_savePublicSwapIdLocally");
5005
+ }
5006
+ }
5007
+ }
5008
+
5009
+ /**
5010
+ * @private
5011
+ * @return {string[]}
5012
+ */
5013
+ _getPublicSwapIdsSavedLocally() {
5014
+ if (typeof window !== "undefined") {
5015
+ try {
5016
+ const saved = localStorage.getItem("publicSwapIds");
5017
+ return typeof saved === "string" && saved.length > 0 ? saved.split(",") : [];
5018
+ } catch (e) {
5019
+ improveAndRethrow(e, "_getPublicSwapIdsSavedLocally");
5020
+ }
5021
+ }
5022
+ }
5023
+
5024
+ /**
5025
+ * @param coinOrTicker {Coin|string}
5026
+ * @return {string} icon URL (ready to use)
5027
+ */
5028
+ getAssetIconUrl(coinOrTicker) {
5029
+ return this._swapProvider.getIconUrl(coinOrTicker);
5030
+ }
5031
+
5032
+ /**
5033
+ * @param ticker {string}
5034
+ * @return {Coin|null}
5035
+ */
5036
+ getCoinByTickerIfPresent(ticker) {
5037
+ return this._swapProvider.getCoinByTickerIfPresent(ticker);
5038
+ }
5039
+
5040
+ /**
5041
+ * TODO: [feature, moderate] add other fiat currencies support. task_id=5490e21b8b9c4f89a2247b28db3c9e0a
5042
+ * @param asset {Coin}
5043
+ * @return {Promise<string|null>}
5044
+ */
5045
+ async getAssetToUsdtRate(asset) {
5046
+ try {
5047
+ var _result$rate;
5048
+ const result = await this._swapProvider.getCoinToUSDTRate(asset);
5049
+ return (_result$rate = result == null ? void 0 : result.rate) != null ? _result$rate : null;
5050
+ } catch (e) {
5051
+ improveAndRethrow(e, "getAssetToUsdtRate");
5052
+ }
5053
+ }
5054
+
5055
+ /**
5056
+ * @param asset {Coin}
5057
+ * @param address {string}
5058
+ * @return {boolean}
5059
+ */
5060
+ isAddressValidForAsset(asset, address) {
5061
+ try {
5062
+ return this._swapProvider.isAddressValidForAsset(asset, address);
5063
+ } catch (e) {
5064
+ improveAndRethrow(e, "isAddressValidForAsset");
5065
+ }
5066
+ }
5067
+
5068
+ /**
5069
+ * Retrieves token by contract address.
5070
+ *
5071
+ * @param addressString {string}
5072
+ * @return {Promise<Coin|null>}
5073
+ */
5074
+ async getTokenByContractAddress(addressString) {
5075
+ try {
5076
+ if (!addressString) return null;
5077
+ const addressLowerCase = addressString.toLowerCase();
5078
+ const allCoins = await this._swapProvider.getAllSupportedCurrencies();
5079
+ if (allCoins.result) {
5080
+ return allCoins.coins.find(coin => coin.tokenAddress && coin.tokenAddress.toLowerCase() === addressLowerCase);
5081
+ }
5082
+ } catch (e) {
5083
+ Logger.logError(e, "getTokenByContractAddress");
5084
+ }
5085
+ return null;
5086
+ }
5087
+
5088
+ /**
5089
+ * @param asset {Coin}
5090
+ * @return {string|null}
5091
+ */
5092
+ getExtraIdNameIfPresentForAsset(asset) {
5093
+ try {
5094
+ return this._swapProvider.getExtraIdNameIfPresent(asset);
5095
+ } catch (e) {
5096
+ improveAndRethrow(e, "getExtraIdNameIfPresentForAsset");
5097
+ }
5098
+ }
5099
+ }
5100
+ PublicSwapService.PUBLIC_SWAP_CREATED_EVENT = "publicSwapCreatedEvent";
5101
+ PublicSwapService.PUBLIC_SWAPS_COMMON_ERRORS = {
5102
+ REQUESTS_LIMIT_EXCEEDED: "requestsLimitExceeded"
5103
+ };
5104
+ PublicSwapService.PUBLIC_SWAP_DETAILS_FAIL_REASONS = {
5105
+ AMOUNT_LESS_THAN_MIN_SWAPPABLE: "amountLessThanMinSwappable",
5106
+ AMOUNT_HIGHER_THAN_MAX_SWAPPABLE: "amountHigherThanMaxSwappable",
5107
+ PAIR_NOT_SUPPORTED: "pairNotSupported"
5108
+ };
5109
+ PublicSwapService._fiatDecimalsCount = FiatCurrenciesService.getCurrencyDecimalCountByCode("USD");
5110
+
5111
+ export { AmountUtils, ApiGroup, ApiGroups, AssetIcon, AxiosAdapter, BaseSwapCreationInfo, Blockchain, Button, Cache, CacheAndConcurrentRequestsResolver, CachedRobustExternalApiCallerService, CancelProcessing, Coin, EmailsApi, ExistingSwap, ExistingSwapWithFiatData, ExternalApiProvider, FiatCurrenciesService, LoadingDots, Logger, LogsStorage, Protocol, PublicSwapService, RobustExternalAPICallerService, SupportChat, SwapProvider, SwapUtils, SwapspaceSwapProvider, getQueryParameterSingleValue, getQueryParameterValues, handleClickOutside, improveAndRethrow, logErrorOrOutputToConsole, postponeExecution, removeQueryParameterAndValues, safeStringify, saveQueryParameterAndValues, useCallHandlingErrors, useReferredState };
1357
5112
  //# sourceMappingURL=index.modern.js.map