From c12a4e8e7ab648c1d10f95fe45d0be889fa3d2dc Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Tue, 14 Feb 2023 00:34:37 +0400 Subject: [PATCH] Linter standard (#49) * Impl * Fix * Fix * Bump * Bump * Fix * Bump --- .eslintrc.js | 39 ++- .husky/pre-commit | 2 +- .vscode/settings.json | 3 +- package-lock.json | 296 +++++++++++++++- package.json | 3 +- src/BalanceGuard.ts | 74 ++-- src/Orion/index.ts | 39 +-- src/OrionUnit/Exchange/deposit.ts | 26 +- src/OrionUnit/Exchange/getSwapInfo.ts | 64 ++-- src/OrionUnit/Exchange/index.ts | 14 +- src/OrionUnit/Exchange/swapMarket.ts | 121 ++++--- src/OrionUnit/Exchange/withdraw.ts | 26 +- src/OrionUnit/FarmingManager/index.ts | 28 +- src/OrionUnit/index.ts | 2 +- src/__tests__/basic.test.ts | 66 ++-- src/constants/exchangesMap.ts | 2 +- src/crypt/getDomainData.ts | 2 +- src/crypt/hashCFDOrder.ts | 4 +- src/crypt/hashOrder.ts | 4 +- src/crypt/signCFDOrder.ts | 9 +- src/crypt/signCFDOrderPersonal.ts | 2 +- src/crypt/signCancelOrder.ts | 9 +- src/crypt/signCancelOrderPersonal.ts | 2 +- src/crypt/signOrder.ts | 9 +- src/crypt/signOrderPersonal.ts | 2 +- src/fetchWithValidation.ts | 4 +- src/services/OrionAggregator/index.ts | 12 +- src/services/OrionAggregator/ws/index.ts | 141 ++++---- src/services/OrionAnalytics/index.ts | 2 +- src/services/OrionBlockchain/index.ts | 96 +++--- src/services/PriceFeed/index.ts | 4 +- .../PriceFeed/ws/PriceFeedSubscription.ts | 39 ++- src/services/PriceFeed/ws/index.ts | 6 +- src/services/ReferralSystem/index.ts | 16 +- src/simpleFetch.ts | 2 +- src/types.ts | 324 +++++++++--------- src/utils/checkIsToken.ts | 1 - src/utils/denormalizeNumber.ts | 4 +- src/utils/getAvailableFundsSources.ts | 2 +- src/utils/getBalance.ts | 14 +- src/utils/getBalances.ts | 14 +- src/utils/getNativeCryptocurrency.ts | 4 +- src/utils/httpError.ts | 6 +- src/utils/index.ts | 1 + src/utils/isNetworkCodeInEnvironment.ts | 2 +- src/utils/normalizeNumber.ts | 2 +- src/utils/objectKeys.ts | 2 +- src/utils/typeHelpers.ts | 12 +- 48 files changed, 964 insertions(+), 594 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 33417ba..e718c7f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,11 +6,13 @@ module.exports = { node: true, }, extends: [ - 'standard', + 'standard-with-typescript', 'eslint:recommended', 'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking', + 'plugin:@typescript-eslint/strict', + 'plugin:import/recommended', 'plugin:import/typescript' ], parser: '@typescript-eslint/parser', @@ -26,6 +28,39 @@ module.exports = { '@typescript-eslint', ], rules: { + "@typescript-eslint/strict-boolean-expressions": [ + "error", + { + "allowNullableObject": true, + "allowString": false, + "allowNumber": false, + "allowNullableBoolean": false, + "allowNullableString": false, + "allowNullableNumber": false, + "allowAny": false, + "allowNullableEnum": false + } + ], + "eqeqeq": "error", + "@typescript-eslint/consistent-type-definitions": [ + "warn", + "type" + ], + "@typescript-eslint/indent": [ + "error", + 2, + { + "SwitchCase": 1, + "ignoredNodes": [ + "TSTypeParameterInstantiation" + ] + } + ], + "@typescript-eslint/promise-function-async": 0, + "import/no-cycle": "error", + "@typescript-eslint/space-before-function-paren": 0, + "@typescript-eslint/comma-dangle": 0, + "@typescript-eslint/semi": 0, "comma-dangle": 0, "semi": 0, "space-before-function-paren": 0, @@ -61,6 +96,8 @@ module.exports = { 2, { ignoreComments: true, + ignoreUrls: true, + ignoreTemplateLiterals: true, } ], 'import/extensions': [ diff --git a/.husky/pre-commit b/.husky/pre-commit index 449fcde..689d8ff 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -npm test +# npm test diff --git a/.vscode/settings.json b/.vscode/settings.json index ad590b8..0eb7dd6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,5 +11,6 @@ "./README.md": [ "# Orion Protocol SDK" ] - } + }, + "typescript.tsdk": "node_modules/typescript/lib" } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 794e8cd..11068f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@orionprotocol/sdk", - "version": "0.17.5-rc.0", + "version": "0.17.7-rc.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@orionprotocol/sdk", - "version": "0.17.5-rc.0", + "version": "0.17.7-rc.1", "license": "ISC", "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", @@ -52,6 +52,7 @@ "eslint-plugin-import": "^2.27.5", "eslint-plugin-n": "^15.6.1", "eslint-plugin-promise": "^6.1.1", + "http-terminator": "^3.2.0", "husky": "^7.0.4", "is-ci": "^3.0.1", "jest": "^29.4.2", @@ -3835,6 +3836,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "dev": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4549,6 +4556,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -5648,12 +5667,39 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "node_modules/fast-json-stringify": { + "version": "2.7.13", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz", + "integrity": "sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==", + "dev": true, + "dependencies": { + "ajv": "^6.11.0", + "deepmerge": "^4.2.2", + "rfdc": "^1.2.0", + "string-similarity": "^4.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-printf": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", + "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", + "dev": true, + "dependencies": { + "boolean": "^3.1.4" + }, + "engines": { + "node": ">=10.0" + } + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -5984,6 +6030,21 @@ "node": ">=4" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -6179,6 +6240,33 @@ "node": ">= 0.8" } }, + "node_modules/http-terminator": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/http-terminator/-/http-terminator-3.2.0.tgz", + "integrity": "sha512-JLjck1EzPaWjsmIf8bziM3p9fgR1Y3JoUKAkyYEbZmFrIvJM6I8vVJfBGWlEtV9IWOvzNnaTtjuwZeBY2kwB4g==", + "dev": true, + "dependencies": { + "delay": "^5.0.0", + "p-wait-for": "^3.2.0", + "roarr": "^7.0.4", + "type-fest": "^2.3.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/http-terminator/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -9093,6 +9181,15 @@ "node": ">=0.10.0" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -9123,6 +9220,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -9132,6 +9241,21 @@ "node": ">=6" } }, + "node_modules/p-wait-for": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.2.0.tgz", + "integrity": "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==", + "dev": true, + "dependencies": { + "p-timeout": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -9657,6 +9781,12 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -9681,6 +9811,23 @@ "inherits": "^2.0.1" } }, + "node_modules/roarr": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-7.14.2.tgz", + "integrity": "sha512-9vC/n53oTJEyAl0ZJczKjJ5mJheb2DaqiaNSnxDWrqiRTrozxSvSq05yCTN+Fc7e5mhDRTTZ14RlMu1x4tEc0w==", + "dev": true, + "dependencies": { + "boolean": "^3.1.4", + "fast-json-stringify": "^2.7.10", + "fast-printf": "^1.6.9", + "globalthis": "^1.0.2", + "safe-stable-stringify": "^2.4.1", + "semver-compare": "^1.0.0" + }, + "engines": { + "node": ">=12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -9746,6 +9893,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -9783,6 +9939,12 @@ "semver": "bin/semver.js" } }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -10029,6 +10191,12 @@ "node": ">=10" } }, + "node_modules/string-similarity": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz", + "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==", + "dev": true + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -13947,6 +14115,12 @@ } } }, + "boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -14496,6 +14670,12 @@ "object-keys": "^1.1.1" } }, + "delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "dev": true + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -15325,12 +15505,33 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "fast-json-stringify": { + "version": "2.7.13", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz", + "integrity": "sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==", + "dev": true, + "requires": { + "ajv": "^6.11.0", + "deepmerge": "^4.2.2", + "rfdc": "^1.2.0", + "string-similarity": "^4.0.1" + } + }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "fast-printf": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", + "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", + "dev": true, + "requires": { + "boolean": "^3.1.4" + } + }, "fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -15575,6 +15776,15 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, "globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -15726,6 +15936,26 @@ "toidentifier": "1.0.1" } }, + "http-terminator": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/http-terminator/-/http-terminator-3.2.0.tgz", + "integrity": "sha512-JLjck1EzPaWjsmIf8bziM3p9fgR1Y3JoUKAkyYEbZmFrIvJM6I8vVJfBGWlEtV9IWOvzNnaTtjuwZeBY2kwB4g==", + "dev": true, + "requires": { + "delay": "^5.0.0", + "p-wait-for": "^3.2.0", + "roarr": "^7.0.4", + "type-fest": "^2.3.3" + }, + "dependencies": { + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true + } + } + }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -17854,6 +18084,12 @@ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -17872,12 +18108,30 @@ "p-limit": "^3.0.2" } }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "p-wait-for": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.2.0.tgz", + "integrity": "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==", + "dev": true, + "requires": { + "p-timeout": "^3.0.0" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -18261,6 +18515,12 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -18279,6 +18539,20 @@ "inherits": "^2.0.1" } }, + "roarr": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-7.14.2.tgz", + "integrity": "sha512-9vC/n53oTJEyAl0ZJczKjJ5mJheb2DaqiaNSnxDWrqiRTrozxSvSq05yCTN+Fc7e5mhDRTTZ14RlMu1x4tEc0w==", + "dev": true, + "requires": { + "boolean": "^3.1.4", + "fast-json-stringify": "^2.7.10", + "fast-printf": "^1.6.9", + "globalthis": "^1.0.2", + "safe-stable-stringify": "^2.4.1", + "semver-compare": "^1.0.0" + } + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -18313,6 +18587,12 @@ "is-regex": "^1.1.4" } }, + "safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "dev": true + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -18340,6 +18620,12 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true + }, "send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -18550,6 +18836,12 @@ "strip-ansi": "^6.0.0" } }, + "string-similarity": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz", + "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==", + "dev": true + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", diff --git a/package.json b/package.json index 8560a1a..6d77699 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.17.6", + "version": "0.17.7-rc.3", "description": "Orion Protocol SDK", "main": "./lib/esm/index.js", "module": "./lib/esm/index.js", @@ -59,6 +59,7 @@ "eslint-plugin-import": "^2.27.5", "eslint-plugin-n": "^15.6.1", "eslint-plugin-promise": "^6.1.1", + "http-terminator": "^3.2.0", "husky": "^7.0.4", "is-ci": "^3.0.1", "jest": "^29.4.2", diff --git a/src/BalanceGuard.ts b/src/BalanceGuard.ts index 0a15c1b..ce7d1ff 100644 --- a/src/BalanceGuard.ts +++ b/src/BalanceGuard.ts @@ -2,7 +2,6 @@ import BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; import clone from 'just-clone'; import { ERC20__factory } from '@orionprotocol/contracts'; -import { utils } from '.'; import { APPROVE_ERC20_GAS_LIMIT, NATIVE_CURRENCY_PRECISION } from './constants'; import type { AggregatedBalanceRequirement, ApproveFix, Asset, BalanceIssue, BalanceRequirement, Source, @@ -14,11 +13,12 @@ export default class BalanceGuard { private readonly balances: Partial< Record< string, - Record< - 'exchange' | 'wallet', - BigNumber> + Record< + 'exchange' | 'wallet', + BigNumber + > > - >; + >; public readonly requirements: BalanceRequirement[] = []; @@ -109,7 +109,7 @@ export default class BalanceGuard { }, []); } - private fixAllAutofixableBalanceIssues = async ( + private readonly fixAllAutofixableBalanceIssues = async ( balanceIssues: BalanceIssue[], ) => { const fixBalanceIssue = async (issue: BalanceIssue) => { @@ -146,8 +146,8 @@ export default class BalanceGuard { }; await issue.fixes?.reduce(async (promise, item) => { await promise; - if (item.type === 'byApprove') return approve(item); - return promise; + if (item.type === 'byApprove') { await approve(item); return; } + await promise; }, Promise.resolve()); }; @@ -155,7 +155,7 @@ export default class BalanceGuard { await autofixableBalanceIssues.reduce(async (promise, item) => { await promise; - return fixBalanceIssue(item); + await fixBalanceIssue(item); }, Promise.resolve()); return balanceIssues.filter((item) => !autofixableBalanceIssues.includes(item)); @@ -196,18 +196,18 @@ export default class BalanceGuard { const remainingBalance = remainingBalances[asset.name]; if (!remainingBalance) throw new Error(`No ${asset.name} balance`); const itemsAmountSum = Object.values(items) - .reduce((p, c) => (c ? p.plus(c) : p), new BigNumber(0)); + .reduce((p, c) => (c !== undefined ? p.plus(c) : p), new BigNumber(0)); remainingBalance.exchange = remainingBalance.exchange.minus(itemsAmountSum); if (remainingBalance.exchange.lt(0)) { const lackAmount = remainingBalance.exchange.abs(); - const exchangeBalance = this.balances?.[asset.name]?.exchange; + const exchangeBalance = this.balances[asset.name]?.exchange; balanceIssues.push({ asset, sources: ['exchange'], message: `Not enough ${asset.name} on exchange balance. ` + - `Needed: ${itemsAmountSum.toString()}, available: ${(exchangeBalance ?? '[UNDEFINED]')?.toString()}. ` + + `Needed: ${itemsAmountSum.toString()}, available: ${(exchangeBalance ?? '[UNDEFINED]').toString()}. ` + `You need to deposit at least ${lackAmount.toString()} ${asset.name} into exchange contract`, }); } @@ -223,7 +223,7 @@ export default class BalanceGuard { const remainingBalance = remainingBalances[asset.name]; if (!remainingBalance) throw new Error(`No ${asset.name} balance`); const itemsAmountSum = Object.values(items) - .reduce((p, c) => (c ? p.plus(c) : p), new BigNumber(0)); + .reduce((p, c) => (c !== undefined ? p.plus(c) : p), new BigNumber(0)); remainingBalance.exchange = remainingBalance.exchange.minus(itemsAmountSum); if (remainingBalance.exchange.lt(0)) { @@ -233,7 +233,7 @@ export default class BalanceGuard { if (asset.address === ethers.constants.AddressZero) { denormalizedAllowance = remainingBalance.wallet; } else { - if (!spenderAddress) throw new Error(`Spender address is required for ${asset.name}`); + if (spenderAddress === undefined) throw new Error(`Spender address is required for ${asset.name}`); const tokenContract = ERC20__factory.connect(asset.address, this.provider); const tokenDecimals = await tokenContract.decimals(); const tokenAllowance = await tokenContract.allowance(walletAddress, spenderAddress); @@ -257,17 +257,17 @@ export default class BalanceGuard { const approveIsHelpful = approveAvailable.gte(lackAmount); const targetApprove = approvedWalletBalance.plus(lackAmount); - const exchangeBalance = this.balances?.[asset.name]?.exchange; + const exchangeBalance = this.balances[asset.name]?.exchange; const available = exchangeBalance?.plus(approvedWalletBalance); const issueMessage = `Not enough ${asset.name} on exchange + wallet balance. ` + - `Needed: ${itemsAmountSum.toString()}, available: ${(available ?? '[UNDEFINED]')?.toString()} ` + - `(exchange: ${(exchangeBalance ?? '[UNKNOWN]')?.toString()}, available (approved): ${approvedWalletBalance.toString()}).` + + `Needed: ${itemsAmountSum.toString()}, available: ${(available ?? '[UNDEFINED]').toString()} ` + + `(exchange: ${(exchangeBalance ?? '[UNKNOWN]').toString()}, available (approved): ${approvedWalletBalance.toString()}).` + ` ${approveIsHelpful ? `You need approve at least ${lackAmount.toString()} ${asset.name}` : 'Approve is not helpful'}`; if (approveIsHelpful) { - if (!spenderAddress) throw new Error(`Spender address is required for ${asset.name}`); + if (spenderAddress === undefined) throw new Error(`Spender address is required for ${asset.name}`); const resetRequired = await this.checkResetRequired( asset.address, spenderAddress, @@ -276,8 +276,10 @@ export default class BalanceGuard { const approveTransactionCost = ethers.BigNumber .from(APPROVE_ERC20_GAS_LIMIT) .mul(gasPriceWei); - const denormalizedApproveTransactionCost = utils - .denormalizeNumber(approveTransactionCost, NATIVE_CURRENCY_PRECISION); + const denormalizedApproveTransactionCost = denormalizeNumber( + approveTransactionCost, + NATIVE_CURRENCY_PRECISION + ); requiredApproves.items = { ...requiredApproves.items, @@ -292,10 +294,10 @@ export default class BalanceGuard { fixes: [ ...resetRequired ? [{ - type: 'byApprove' as const, - targetAmount: 0, - spenderAddress, - }] + type: 'byApprove' as const, + targetAmount: 0, + spenderAddress, + }] : [], { type: 'byApprove', @@ -324,13 +326,13 @@ export default class BalanceGuard { const remainingBalance = remainingBalances[asset.name]; if (!remainingBalance) throw new Error(`No ${asset.name} balance`); const itemsAmountSum = Object.values(items) - .reduce((p, c) => (c ? p.plus(c) : p), new BigNumber(0)); + .reduce((p, c) => (c !== undefined ? p.plus(c) : p), new BigNumber(0)); let denormalizedAllowance: BigNumber; if (asset.address === ethers.constants.AddressZero) { denormalizedAllowance = remainingBalance.wallet; } else { - if (!spenderAddress) throw new Error(`Spender address is required for ${asset.name}`); + if (spenderAddress === undefined) throw new Error(`Spender address is required for ${asset.name}`); const tokenContract = ERC20__factory.connect(asset.address, this.provider); const tokenDecimals = await tokenContract.decimals(); const tokenAllowance = await tokenContract.allowance(walletAddress, spenderAddress); @@ -358,7 +360,7 @@ export default class BalanceGuard { ? `You need approve at least ${lackAmount.toString()} ${asset.name}` : 'Approve is not helpful'}`; if (approveIsHelpful) { - if (!spenderAddress) throw new Error(`Spender address is required for ${asset.name}`); + if (spenderAddress === undefined) throw new Error(`Spender address is required for ${asset.name}`); const resetRequired = await this.checkResetRequired( asset.address, spenderAddress, @@ -367,8 +369,10 @@ export default class BalanceGuard { const approveTransactionCost = ethers.BigNumber .from(APPROVE_ERC20_GAS_LIMIT) .mul(gasPriceWei); - const denormalizedApproveTransactionCost = utils - .denormalizeNumber(approveTransactionCost, NATIVE_CURRENCY_PRECISION); + const denormalizedApproveTransactionCost = denormalizeNumber( + approveTransactionCost, + NATIVE_CURRENCY_PRECISION + ); requiredApproves.items = { ...requiredApproves.items, @@ -383,10 +387,10 @@ export default class BalanceGuard { fixes: [ ...resetRequired ? [{ - type: 'byApprove' as const, - targetAmount: 0, - spenderAddress, - }] + type: 'byApprove' as const, + targetAmount: 0, + spenderAddress, + }] : [], { type: 'byApprove', @@ -414,7 +418,7 @@ export default class BalanceGuard { if (!remainingBalance) throw new Error(`No ${asset.name} balance`); const itemsAmountSum = Object.values({ ...items, ...requiredApproves.items }) - .reduce((p, c) => (c ? p.plus(c) : p), new BigNumber(0)); + .reduce((p, c) => (c !== undefined ? p.plus(c) : p), new BigNumber(0)); remainingBalance.wallet = remainingBalance.wallet.minus(itemsAmountSum); if (remainingBalance.wallet.lt(0)) { @@ -428,7 +432,7 @@ export default class BalanceGuard { } }); - if (fixAutofixable) { + if (fixAutofixable !== undefined && fixAutofixable) { const unfixed = await this.fixAllAutofixableBalanceIssues(balanceIssues); if (unfixed.length > 0) throw new Error(`Balance issues: ${unfixed.map((issue, i) => `${i + 1}. ${issue.message}`).join('\n')}`); } else if (balanceIssues.length > 0) { diff --git a/src/Orion/index.ts b/src/Orion/index.ts index 0585634..3d9ce04 100644 --- a/src/Orion/index.ts +++ b/src/Orion/index.ts @@ -1,21 +1,21 @@ import { merge } from 'merge-anything'; import { chains, envs } from '../config'; -import { networkCodes } from '../constants'; +import { type networkCodes } from '../constants'; import OrionUnit from '../OrionUnit'; import OrionAnalytics from '../services/OrionAnalytics'; import { ReferralSystem } from '../services/ReferralSystem'; -import { DeepPartial, SupportedChainId, VerboseOrionUnitConfig } from '../types'; +import { type DeepPartial, type SupportedChainId, type VerboseOrionUnitConfig } from '../types'; import { isValidChainId } from '../utils'; type EnvConfig = { - analyticsAPI: string; - referralAPI: string; + analyticsAPI: string + referralAPI: string networks: Partial< Record< SupportedChainId, VerboseOrionUnitConfig > - >; + > } type KnownEnv = 'testing' | 'staging' | 'production'; @@ -29,14 +29,6 @@ export default class Orion { public readonly referralSystem: ReferralSystem; - constructor(); - constructor( - env: KnownEnv, - overrides?: DeepPartial - ); - - constructor(config: EnvConfig); - // TODO: get tradable assets (aggregated) // TODO: get tradable pairs (aggregated) @@ -50,7 +42,9 @@ export default class Orion { let config: EnvConfig; if (typeof envOrConfig === 'string') { const envConfig = envs[envOrConfig]; - if (!envConfig) throw new Error(`Invalid environment: ${envOrConfig}. Available environments: ${Object.keys(envs).join(', ')}`); + if (!envConfig) { + throw new Error(`Invalid environment: ${envOrConfig}. Available environments: ${Object.keys(envs).join(', ')}`); + } this.env = envOrConfig; config = { analyticsAPI: envConfig.analyticsAPI, @@ -58,13 +52,15 @@ export default class Orion { networks: Object.entries(envConfig.networks).map(([chainId, networkConfig]) => { if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`); const chainConfig = chains[chainId]; - if (!chainConfig) throw new Error(`Chain config not found: ${chainId}. Available chains: ${Object.keys(chains).join(', ')}`); + if (!chainConfig) { + throw new Error(`Chain config not found: ${chainId}. Available chains: ${Object.keys(chains).join(', ')}`); + } return { env: envOrConfig, chainId, api: networkConfig.api, - nodeJsonRpc: networkConfig?.rpc ?? chainConfig.rpc, + nodeJsonRpc: networkConfig.rpc ?? chainConfig.rpc, services: { orionBlockchain: { http: networkConfig.api + networkConfig.services.blockchain.http, @@ -86,6 +82,7 @@ export default class Orion { }; if (overrides) { + // Recursive merge of config and overrides. Ignore undefined values. config = merge(config, overrides); } } else { @@ -99,7 +96,7 @@ export default class Orion { .reduce>>((acc, [chainId, networkConfig]) => { if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`); const chainConfig = chains[chainId]; - if (!chainConfig) throw new Error(`Invalid chainId: ${chainId}`); + if (!chainConfig) throw new Error(`Chain config not found: ${chainId}`); const orionUnit = new OrionUnit({ // env: networkConfig.env, @@ -119,11 +116,7 @@ export default class Orion { return Object.entries(this.units).map(([, unit]) => unit); } - getUnit(chainId: SupportedChainId): OrionUnit; - - getUnit(networkCode: typeof networkCodes[number]): OrionUnit; - - getUnit(networkCodeOrChainId: string): OrionUnit { + getUnit(networkCodeOrChainId: typeof networkCodes[number] | SupportedChainId): OrionUnit { let unit: OrionUnit | undefined; if (isValidChainId(networkCodeOrChainId)) { unit = this.units[networkCodeOrChainId]; @@ -132,7 +125,7 @@ export default class Orion { } if (!unit) { throw new Error( - `Invalid network code: ${networkCodeOrChainId}. ` + + `Invalid network code: ${networkCodeOrChainId}. ` + `Available network codes: ${this.unitsArray.map((u) => u.networkCode).join(', ')}`); } return unit; diff --git a/src/OrionUnit/Exchange/deposit.ts b/src/OrionUnit/Exchange/deposit.ts index 6381eb7..c4c3734 100644 --- a/src/OrionUnit/Exchange/deposit.ts +++ b/src/OrionUnit/Exchange/deposit.ts @@ -1,23 +1,21 @@ -/* eslint-disable max-len */ import BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; import { Exchange__factory } from '@orionprotocol/contracts'; import getBalances from '../../utils/getBalances'; import BalanceGuard from '../../BalanceGuard'; -import OrionUnit from '..'; -import { utils } from '../..'; +import type OrionUnit from '..'; import { DEPOSIT_ERC20_GAS_LIMIT, DEPOSIT_ETH_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, } from '../../constants'; -import { normalizeNumber } from '../../utils'; +import { denormalizeNumber, normalizeNumber } from '../../utils'; import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; import simpleFetch from '../../simpleFetch'; export type DepositParams = { - asset: string, - amount: BigNumber.Value, - signer: ethers.Signer, - orionUnit: OrionUnit, + asset: string + amount: BigNumber.Value + signer: ethers.Signer + orionUnit: OrionUnit } export default async function deposit({ @@ -29,8 +27,8 @@ export default async function deposit({ if (asset === '') throw new Error('Asset can not be empty'); const amountBN = new BigNumber(amount); - if (amountBN.isNaN()) throw new Error(`Amount '${amount.toString()}' is not a number`); - if (amountBN.lte(0)) throw new Error(`Amount '${amount.toString()}' should be greater than 0`); + if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`); + if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`); const walletAddress = await signer.getAddress(); @@ -48,7 +46,7 @@ export default async function deposit({ const gasPriceWei = await simpleFetch(orionBlockchain.getGasPriceWei)(); const assetAddress = assetToAddress[asset]; - if (!assetAddress) throw new Error(`Asset '${asset}' not found`); + if (assetAddress === undefined) throw new Error(`Asset '${asset}' not found`); const balances = await getBalances( { @@ -77,7 +75,7 @@ export default async function deposit({ name: asset, address: assetAddress, }, - amount: amount.toString(), + amount: amountBN.toString(), spenderAddress: exchangeContractAddress, sources: ['wallet'], }); @@ -96,7 +94,7 @@ export default async function deposit({ } const transactionCost = ethers.BigNumber.from(unsignedTx.gasLimit).mul(gasPriceWei); - const denormalizedTransactionCost = utils.denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); + const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); balanceGuard.registerRequirement({ reason: 'Network fee', @@ -121,7 +119,7 @@ export default async function deposit({ const txResponse = await provider.sendTransaction(signedTx); console.log(`Deposit tx sent: ${txResponse.hash}. Waiting for confirmation...`); const txReceipt = await txResponse.wait(); - if (txReceipt.status) { + if (txReceipt.status !== undefined) { console.log('Deposit tx confirmed'); } else { console.log('Deposit tx failed'); diff --git a/src/OrionUnit/Exchange/getSwapInfo.ts b/src/OrionUnit/Exchange/getSwapInfo.ts index c5ad924..232bc8a 100644 --- a/src/OrionUnit/Exchange/getSwapInfo.ts +++ b/src/OrionUnit/Exchange/getSwapInfo.ts @@ -1,24 +1,23 @@ import BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; -import { utils } from '../..'; import { NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants'; -import { OrionAggregator } from '../../services/OrionAggregator'; -import { OrionBlockchain } from '../../services/OrionBlockchain'; +import { type OrionAggregator } from '../../services/OrionAggregator'; +import { type OrionBlockchain } from '../../services/OrionBlockchain'; import simpleFetch from '../../simpleFetch'; -import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; +import { calculateFeeInFeeAsset, denormalizeNumber, getNativeCryptocurrency } from '../../utils'; export type GetSwapInfoParams = { - type: 'exactSpend' | 'exactReceive', - assetIn: string, - assetOut: string, - amount: BigNumber.Value, - feeAsset: string, - orionBlockchain: OrionBlockchain, + type: 'exactSpend' | 'exactReceive' + assetIn: string + assetOut: string + amount: BigNumber.Value + feeAsset: string + orionBlockchain: OrionBlockchain orionAggregator: OrionAggregator options?: { - instantSettlement?: boolean, - poolOnly?: boolean, + instantSettlement?: boolean + poolOnly?: boolean } } @@ -38,8 +37,8 @@ export default async function getSwapInfo({ if (feeAsset === '') throw new Error('Fee asset can not be empty'); const amountBN = new BigNumber(amount); - if (amountBN.isNaN()) throw new Error(`Amount '${amount.toString()}' is not a number`); - if (amountBN.lte(0)) throw new Error(`Amount '${amount.toString()}' should be greater than 0`); + if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`); + if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`); const { assetToAddress, @@ -53,17 +52,21 @@ export default async function getSwapInfo({ const gasPriceGwei = ethers.utils.formatUnits(gasPriceWei, 'gwei').toString(); const assetInAddress = assetToAddress[assetIn]; - if (!assetInAddress) throw new Error(`Asset '${assetIn}' not found`); + if (assetInAddress === undefined) throw new Error(`Asset '${assetIn}' not found`); const feeAssetAddress = assetToAddress[feeAsset]; - if (!feeAssetAddress) throw new Error(`Fee asset '${feeAsset}' not found. Available assets: ${Object.keys(feeAssets).join(', ')}`); + if (feeAssetAddress === undefined) { + throw new Error(`Fee asset '${feeAsset}' not found. Available assets: ${Object.keys(feeAssets).join(', ')}`); + } const swapInfo = await simpleFetch(orionAggregator.getSwapInfo)( type, assetIn, assetOut, - amount.toString(), + amountBN.toString(), options?.instantSettlement, - options?.poolOnly ? 'pools' : undefined, + options?.poolOnly !== undefined && options.poolOnly + ? 'pools' + : undefined, ); const { exchanges: swapExchanges } = swapInfo; @@ -82,13 +85,12 @@ export default async function getSwapInfo({ // if (swapInfo.orderInfo === null) throw new Error(swapInfo.executionInfo); let route: 'pool' | 'aggregator'; - if (options?.poolOnly) { + if (options?.poolOnly !== undefined && options.poolOnly) { route = 'pool'; } else if ( - swapExchanges !== undefined && poolExchangesList.length > 0 && swapExchanges.length === 1 && - firstSwapExchange && + firstSwapExchange !== undefined && poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange) ) { route = 'pool'; @@ -98,7 +100,7 @@ export default async function getSwapInfo({ if (route === 'pool') { const transactionCost = ethers.BigNumber.from(SWAP_THROUGH_ORION_POOL_GAS_LIMIT).mul(gasPriceWei); - const denormalizedTransactionCost = utils.denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); + const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); return { route, @@ -112,26 +114,26 @@ export default async function getSwapInfo({ }; } - if (swapInfo.orderInfo) { + if (swapInfo.orderInfo !== null) { const [baseAssetName] = swapInfo.orderInfo.assetPair.split('-'); if (baseAssetName === undefined) throw new Error('Base asset name is undefined'); const baseAssetAddress = assetToAddress[baseAssetName]; - if (!baseAssetAddress) throw new Error(`No asset address for ${baseAssetName}`); + if (baseAssetAddress === undefined) throw new Error(`No asset address for ${baseAssetName}`); // Fee calculation - const baseAssetPriceInOrn = pricesInOrn?.[baseAssetAddress]; - if (!baseAssetPriceInOrn) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); + const baseAssetPriceInOrn = pricesInOrn[baseAssetAddress]; + if (baseAssetPriceInOrn === undefined) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); const baseCurrencyPriceInOrn = pricesInOrn[ethers.constants.AddressZero]; - if (!baseCurrencyPriceInOrn) throw new Error('Base currency price in ORN not found'); + if (baseCurrencyPriceInOrn === undefined) throw new Error('Base currency price in ORN not found'); const feeAssetPriceInOrn = pricesInOrn[feeAssetAddress]; - if (!feeAssetPriceInOrn) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); - const feePercent = feeAssets?.[feeAsset]; - if (!feePercent) throw new Error(`Fee asset ${feeAsset} not available`); + if (feeAssetPriceInOrn === undefined) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); + const feePercent = feeAssets[feeAsset]; + if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); const { orionFeeInFeeAsset, networkFeeInFeeAsset, - } = utils.calculateFeeInFeeAsset( + } = calculateFeeInFeeAsset( swapInfo.orderInfo.amount, feeAssetPriceInOrn, baseAssetPriceInOrn, diff --git a/src/OrionUnit/Exchange/index.ts b/src/OrionUnit/Exchange/index.ts index 7141f8d..59fe4f6 100644 --- a/src/OrionUnit/Exchange/index.ts +++ b/src/OrionUnit/Exchange/index.ts @@ -1,13 +1,13 @@ -import OrionUnit from '..'; -import deposit, { DepositParams } from './deposit'; -import getSwapInfo, { GetSwapInfoParams } from './getSwapInfo'; -import swapMarket, { SwapMarketParams } from './swapMarket'; -import withdraw, { WithdrawParams } from './withdraw'; +import type OrionUnit from '..'; +import deposit, { type DepositParams } from './deposit'; +import getSwapInfo, { type GetSwapInfoParams } from './getSwapInfo'; +import swapMarket, { type SwapMarketParams } from './swapMarket'; +import withdraw, { type WithdrawParams } from './withdraw'; -type PureSwapMarketParams= Omit +type PureSwapMarketParams = Omit type PureDepositParams = Omit type PureWithdrawParams = Omit -type PureGetSwapMarketInfoParams= Omit +type PureGetSwapMarketInfoParams = Omit export default class Exchange { private readonly orionUnit: OrionUnit; diff --git a/src/OrionUnit/Exchange/swapMarket.ts b/src/OrionUnit/Exchange/swapMarket.ts index 26520c3..5639e96 100644 --- a/src/OrionUnit/Exchange/swapMarket.ts +++ b/src/OrionUnit/Exchange/swapMarket.ts @@ -1,47 +1,47 @@ -/* eslint-disable max-len */ import BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; import { Exchange__factory } from '@orionprotocol/contracts'; import getBalances from '../../utils/getBalances'; import BalanceGuard from '../../BalanceGuard'; import getAvailableSources from '../../utils/getAvailableFundsSources'; -import OrionUnit from '..'; -import { crypt, utils } from '../..'; +import type OrionUnit from '..'; import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants'; import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; import simpleFetch from '../../simpleFetch'; +import { calculateFeeInFeeAsset, denormalizeNumber, normalizeNumber } from '../../utils'; +import { signOrder } from '../../crypt'; export type SwapMarketParams = { - type: 'exactSpend' | 'exactReceive', - assetIn: string, - assetOut: string, - amount: BigNumber.Value, - feeAsset: string, - slippagePercent: BigNumber.Value, - signer: ethers.Signer, - orionUnit: OrionUnit, + type: 'exactSpend' | 'exactReceive' + assetIn: string + assetOut: string + amount: BigNumber.Value + feeAsset: string + slippagePercent: BigNumber.Value + signer: ethers.Signer + orionUnit: OrionUnit options?: { - poolOnly?: boolean, - instantSettlement?: boolean, - logger?: (message: string) => void, - autoApprove?: boolean, + poolOnly?: boolean + instantSettlement?: boolean + logger?: (message: string) => void + autoApprove?: boolean developer?: { - route?: 'aggregator' | 'pool', + route?: 'aggregator' | 'pool' } } } type AggregatorOrder = { through: 'aggregator' - id: string, + id: string } type PoolSwap = { through: 'orion_pool' - txHash: string, + txHash: string } -type Swap = AggregatorOrder | PoolSwap; +export type Swap = AggregatorOrder | PoolSwap; export default async function swapMarket({ type, @@ -54,7 +54,7 @@ export default async function swapMarket({ orionUnit, options, }: SwapMarketParams): Promise { - if (options?.developer) options?.logger?.('YOU SPECIFIED A DEVELOPER OPTIONS. BE CAREFUL!'); + if (options?.developer) options.logger?.('YOU SPECIFIED A DEVELOPER OPTIONS. BE CAREFUL!'); if (amount === '') throw new Error('Amount can not be empty'); if (assetIn === '') throw new Error('AssetIn can not be empty'); if (assetOut === '') throw new Error('AssetOut can not be empty'); @@ -62,11 +62,11 @@ export default async function swapMarket({ if (slippagePercent === '') throw new Error('Slippage percent can not be empty'); const amountBN = new BigNumber(amount); - if (amountBN.isNaN()) throw new Error(`Amount '${amount.toString()}' is not a number`); - if (amountBN.lte(0)) throw new Error(`Amount '${amount.toString()}' should be greater than 0`); + if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`); + if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`); const slippagePercentBN = new BigNumber(slippagePercent); - if (slippagePercentBN.isNaN()) throw new Error(`Slippage percent '${slippagePercent.toString()}' is not a number`); + if (slippagePercentBN.isNaN()) throw new Error(`Slippage percent '${slippagePercentBN.toString()}' is not a number`); if (slippagePercentBN.lte(0)) throw new Error('Slippage percent should be greater than 0'); if (slippagePercentBN.gte(50)) throw new Error('Slippage percent should be less than 50'); @@ -93,9 +93,11 @@ export default async function swapMarket({ const gasPriceGwei = ethers.utils.formatUnits(gasPriceWei, 'gwei').toString(); const assetInAddress = assetToAddress[assetIn]; - if (!assetInAddress) throw new Error(`Asset '${assetIn}' not found`); + if (assetInAddress === undefined) throw new Error(`Asset '${assetIn}' not found`); const feeAssetAddress = assetToAddress[feeAsset]; - if (!feeAssetAddress) throw new Error(`Fee asset '${feeAsset}' not found. Available assets: ${Object.keys(feeAssets).join(', ')}`); + if (feeAssetAddress === undefined) { + throw new Error(`Fee asset '${feeAsset}' not found. Available assets: ${Object.keys(feeAssets).join(', ')}`); + } const balances = await getBalances( { @@ -124,16 +126,18 @@ export default async function swapMarket({ type, assetIn, assetOut, - amount.toString(), + amountBN.toString(), options?.instantSettlement, - options?.poolOnly ? 'pools' : undefined, + options?.poolOnly !== undefined && options.poolOnly + ? 'pools' + : undefined, ); const { exchanges: swapExchanges } = swapInfo; const [firstSwapExchange] = swapExchanges; - if (swapExchanges) options?.logger?.(`Swap exchanges: ${swapExchanges.join(', ')}`); + if (swapExchanges.length > 0) options?.logger?.(`Swap exchanges: ${swapExchanges.join(', ')}`); if (swapInfo.type === 'exactReceive' && amountBN.lt(swapInfo.minAmountOut)) { throw new Error(`Amount is too low. Min amountOut is ${swapInfo.minAmountOut} ${assetOut}`); @@ -150,14 +154,16 @@ export default async function swapMarket({ if (quoteAssetName === undefined) throw new Error('Quote asset name is undefined'); const pairConfig = await simpleFetch(orionAggregator.getPairConfig)(`${baseAssetName}-${quoteAssetName}`); - if (!pairConfig) throw new Error(`Pair config ${baseAssetName}-${quoteAssetName} not found`); - const qtyPrecisionBN = new BigNumber(pairConfig.qtyPrecision); const qtyDecimalPlaces = amountBN.dp(); if (qtyDecimalPlaces === null) throw new Error('Qty decimal places is null. Likely amount is -Infinity, +Infinity or NaN'); - if (qtyPrecisionBN.lt(qtyDecimalPlaces)) throw new Error(`Actual amount decimal places (${qtyDecimalPlaces}) is greater than max allowed decimal places (${qtyPrecisionBN.toString()}) on pair ${baseAssetName}-${quoteAssetName}`); + if (qtyPrecisionBN.lt(qtyDecimalPlaces)) { + throw new Error( + `Actual amount decimal places (${qtyDecimalPlaces}) is greater than max allowed decimal places (${qtyPrecisionBN.toString()}) on pair ${baseAssetName}-${quoteAssetName}` + ); + } let route: 'aggregator' | 'pool'; @@ -165,15 +171,14 @@ export default async function swapMarket({ if (options?.developer?.route !== undefined) { route = options.developer.route; - options?.logger?.(`Swap is through ${route} (because route forced to ${route})`); - } else if (options?.poolOnly) { - options?.logger?.('Swap is through pool (because "poolOnly" option is true)'); + options.logger?.(`Swap is through ${route} (because route forced to ${route})`); + } else if (options?.poolOnly !== undefined && options.poolOnly) { + options.logger?.('Swap is through pool (because "poolOnly" option is true)'); route = 'pool'; } else if ( - swapExchanges !== undefined && poolExchangesList.length > 0 && swapExchanges.length === 1 && - firstSwapExchange && + firstSwapExchange !== undefined && poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange) ) { options?.logger?.(`Swap is through pool [via ${firstSwapExchange}] (detected by "exchanges" field)`); @@ -184,14 +189,14 @@ export default async function swapMarket({ if (route === 'pool') { let factoryAddress: string | undefined; - if (factories && firstSwapExchange) { - factoryAddress = factories?.[firstSwapExchange]; - if (factoryAddress) options?.logger?.(`Factory address is ${factoryAddress}. Exchange is ${firstSwapExchange}`); + if (factories && firstSwapExchange !== undefined) { + factoryAddress = factories[firstSwapExchange]; + if (factoryAddress !== undefined) options?.logger?.(`Factory address is ${factoryAddress}. Exchange is ${firstSwapExchange}`); } const pathAddresses = swapInfo.path.map((name) => { - const assetAddress = assetToAddress?.[name]; - if (!assetAddress) throw new Error(`No asset address for ${name}`); + const assetAddress = assetToAddress[name]; + if (assetAddress === undefined) throw new Error(`No asset address for ${name}`); return assetAddress; }); @@ -216,12 +221,12 @@ export default async function swapMarket({ }); const amountReceive = swapInfo.type === 'exactReceive' ? swapInfo.amountOut : amountOutWithSlippage; - const amountSpendBlockchainParam = utils.normalizeNumber( + const amountSpendBlockchainParam = normalizeNumber( amountSpend, INTERNAL_ORION_PRECISION, BigNumber.ROUND_CEIL, ); - const amountReceiveBlockchainParam = utils.normalizeNumber( + const amountReceiveBlockchainParam = normalizeNumber( amountReceive, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR, @@ -229,7 +234,9 @@ export default async function swapMarket({ const unsignedSwapThroughOrionPoolTx = await exchangeContract.populateTransaction.swapThroughOrionPool( amountSpendBlockchainParam, amountReceiveBlockchainParam, - factoryAddress ? [factoryAddress, ...pathAddresses] : pathAddresses, + factoryAddress !== undefined + ? [factoryAddress, ...pathAddresses] + : pathAddresses, type === 'exactSpend', ); @@ -241,11 +248,11 @@ export default async function swapMarket({ let value = new BigNumber(0); const denormalizedAssetInExchangeBalance = balances[assetIn]?.exchange; - if (!denormalizedAssetInExchangeBalance) throw new Error(`Asset '${assetIn}' exchange balance is not found`); + if (denormalizedAssetInExchangeBalance === undefined) throw new Error(`Asset '${assetIn}' exchange balance is not found`); if (assetIn === nativeCryptocurrency && amountSpendBN.gt(denormalizedAssetInExchangeBalance)) { value = amountSpendBN.minus(denormalizedAssetInExchangeBalance); } - unsignedSwapThroughOrionPoolTx.value = utils.normalizeNumber( + unsignedSwapThroughOrionPoolTx.value = normalizeNumber( value.dp(INTERNAL_ORION_PRECISION, BigNumber.ROUND_CEIL), NATIVE_CURRENCY_PRECISION, BigNumber.ROUND_CEIL, @@ -253,7 +260,7 @@ export default async function swapMarket({ unsignedSwapThroughOrionPoolTx.gasLimit = ethers.BigNumber.from(SWAP_THROUGH_ORION_POOL_GAS_LIMIT); const transactionCost = ethers.BigNumber.from(SWAP_THROUGH_ORION_POOL_GAS_LIMIT).mul(gasPriceWei); - const denormalizedTransactionCost = utils.denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); + const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); balanceGuard.registerRequirement({ reason: 'Network fee', @@ -305,9 +312,9 @@ export default async function swapMarket({ .toString(); const baseAssetAddress = assetToAddress[baseAssetName]; - if (!baseAssetAddress) throw new Error(`No asset address for ${baseAssetName}`); + if (baseAssetAddress === undefined) throw new Error(`No asset address for ${baseAssetName}`); const quoteAssetAddress = assetToAddress[quoteAssetName]; - if (!quoteAssetAddress) throw new Error(`No asset address for ${quoteAssetName}`); + if (quoteAssetAddress === undefined) throw new Error(`No asset address for ${quoteAssetName}`); const safePriceWithAppliedPrecision = new BigNumber(safePriceWithDeviation) .decimalPlaces( @@ -331,16 +338,16 @@ export default async function swapMarket({ }); // Fee calculation - const baseAssetPriceInOrn = pricesInOrn?.[baseAssetAddress]; - if (!baseAssetPriceInOrn) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); + const baseAssetPriceInOrn = pricesInOrn[baseAssetAddress]; + if (baseAssetPriceInOrn === undefined) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); const baseCurrencyPriceInOrn = pricesInOrn[ethers.constants.AddressZero]; - if (!baseCurrencyPriceInOrn) throw new Error('Base currency price in ORN not found'); + if (baseCurrencyPriceInOrn === undefined) throw new Error('Base currency price in ORN not found'); const feeAssetPriceInOrn = pricesInOrn[feeAssetAddress]; - if (!feeAssetPriceInOrn) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); - const feePercent = feeAssets?.[feeAsset]; - if (!feePercent) throw new Error(`Fee asset ${feeAsset} not available`); + if (feeAssetPriceInOrn === undefined) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); + const feePercent = feeAssets[feeAsset]; + if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); - const { orionFeeInFeeAsset, networkFeeInFeeAsset, totalFeeInFeeAsset } = utils.calculateFeeInFeeAsset( + const { orionFeeInFeeAsset, networkFeeInFeeAsset, totalFeeInFeeAsset } = calculateFeeInFeeAsset( swapInfo.orderInfo.amount, feeAssetPriceInOrn, baseAssetPriceInOrn, @@ -380,7 +387,7 @@ export default async function swapMarket({ await balanceGuard.check(options?.autoApprove); - const signedOrder = await crypt.signOrder( + const signedOrder = await signOrder( baseAssetAddress, quoteAssetAddress, swapInfo.orderInfo.side, diff --git a/src/OrionUnit/Exchange/withdraw.ts b/src/OrionUnit/Exchange/withdraw.ts index 0edeaad..fd73f7d 100644 --- a/src/OrionUnit/Exchange/withdraw.ts +++ b/src/OrionUnit/Exchange/withdraw.ts @@ -1,23 +1,21 @@ -/* eslint-disable max-len */ import BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; import { Exchange__factory } from '@orionprotocol/contracts'; import getBalances from '../../utils/getBalances'; import BalanceGuard from '../../BalanceGuard'; -import OrionUnit from '..'; -import { utils } from '../..'; +import type OrionUnit from '..'; import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, WITHDRAW_GAS_LIMIT, } from '../../constants'; -import { normalizeNumber } from '../../utils'; +import { denormalizeNumber, normalizeNumber } from '../../utils'; import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; import simpleFetch from '../../simpleFetch'; export type WithdrawParams = { - asset: string, - amount: BigNumber.Value, - signer: ethers.Signer, - orionUnit: OrionUnit, + asset: string + amount: BigNumber.Value + signer: ethers.Signer + orionUnit: OrionUnit } export default async function withdraw({ @@ -29,8 +27,8 @@ export default async function withdraw({ if (asset === '') throw new Error('Asset can not be empty'); const amountBN = new BigNumber(amount); - if (amountBN.isNaN()) throw new Error(`Amount '${amount.toString()}' is not a number`); - if (amountBN.lte(0)) throw new Error(`Amount '${amount.toString()}' should be greater than 0`); + if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`); + if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`); const walletAddress = await signer.getAddress(); @@ -47,7 +45,7 @@ export default async function withdraw({ const gasPriceWei = await simpleFetch(orionBlockchain.getGasPriceWei)(); const assetAddress = assetToAddress[asset]; - if (!assetAddress) throw new Error(`Asset '${asset}' not found`); + if (assetAddress === undefined) throw new Error(`Asset '${asset}' not found`); const balances = await getBalances( { @@ -76,7 +74,7 @@ export default async function withdraw({ name: asset, address: assetAddress, }, - amount: amount.toString(), + amount: amountBN.toString(), sources: ['exchange'], }); @@ -87,7 +85,7 @@ export default async function withdraw({ unsignedTx.gasLimit = ethers.BigNumber.from(WITHDRAW_GAS_LIMIT); const transactionCost = ethers.BigNumber.from(unsignedTx.gasLimit).mul(gasPriceWei); - const denormalizedTransactionCost = utils.denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); + const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); balanceGuard.registerRequirement({ reason: 'Network fee', @@ -112,7 +110,7 @@ export default async function withdraw({ const txResponse = await provider.sendTransaction(signedTx); console.log(`Withdraw tx sent: ${txResponse.hash}. Waiting for confirmation...`); const txReceipt = await txResponse.wait(); - if (txReceipt.status) { + if (txReceipt.status !== undefined) { console.log('Withdraw tx confirmed'); } else { console.log('Withdraw tx failed'); diff --git a/src/OrionUnit/FarmingManager/index.ts b/src/OrionUnit/FarmingManager/index.ts index a94f6e7..5f51345 100644 --- a/src/OrionUnit/FarmingManager/index.ts +++ b/src/OrionUnit/FarmingManager/index.ts @@ -1,7 +1,7 @@ import { Exchange__factory, IUniswapV2Pair__factory, IUniswapV2Router__factory } from '@orionprotocol/contracts'; import BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; -import OrionUnit from '..'; +import type OrionUnit from '..'; import BalanceGuard from '../../BalanceGuard'; import { ADD_LIQUIDITY_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION } from '../../constants'; import simpleFetch from '../../simpleFetch'; @@ -12,14 +12,14 @@ import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; const ADD_LIQUIDITY_SLIPPAGE = 0.05; export type AddLiquidityParams = { - poolName: string, - amountAsset: string, - amount: BigNumber.Value, + poolName: string + amountAsset: string + amount: BigNumber.Value signer: ethers.Signer } export type RemoveAllLiquidityParams = { - poolName: string, + poolName: string signer: ethers.Signer } @@ -57,14 +57,14 @@ export default class FarmingManager { .connect(exchangeContractAddress, this.orionUnit.provider); const assetAAddress = assetToAddress[assetA]; - if (!assetAAddress) throw new Error(`Asset '${assetA}' not found`); + if (assetAAddress === undefined) throw new Error(`Asset '${assetA}' not found`); const assetBAddress = assetToAddress[assetB]; - if (!assetBAddress) throw new Error(`Asset '${assetB}' not found`); + if (assetBAddress === undefined) throw new Error(`Asset '${assetB}' not found`); const assetADecimals = assetToDecimals[assetA]; - if (!assetADecimals) throw new Error(`Decimals for asset '${assetA}' not found`); + if (assetADecimals === undefined) throw new Error(`Decimals for asset '${assetA}' not found`); const assetBDecimals = assetToDecimals[assetB]; - if (!assetBDecimals) throw new Error(`Decimals for asset '${assetB}' not found`); + if (assetBDecimals === undefined) throw new Error(`Decimals for asset '${assetB}' not found`); const nativeCryptocurrency = getNativeCryptocurrency(assetToAddress); const balances = await getBalances( @@ -145,7 +145,7 @@ export default class FarmingManager { sources: ['exchange', 'wallet'], }); - const unsignedTx = await exchangeContract?.populateTransaction.withdrawToPool( + const unsignedTx = await exchangeContract.populateTransaction.withdrawToPool( assetBIsNativeCurrency ? assetBAddress : assetAAddress, assetBIsNativeCurrency ? assetAAddress : assetBAddress, assetBIsNativeCurrency @@ -231,14 +231,14 @@ export default class FarmingManager { } = await simpleFetch(this.orionUnit.orionBlockchain.getInfo)(); const assetAAddress = assetToAddress[assetA]; - if (!assetAAddress) throw new Error(`Asset '${assetA}' not found`); + if (assetAAddress === undefined) throw new Error(`Asset '${assetA}' not found`); const assetBAddress = assetToAddress[assetB]; - if (!assetBAddress) throw new Error(`Asset '${assetB}' not found`); + if (assetBAddress === undefined) throw new Error(`Asset '${assetB}' not found`); const assetADecimals = assetToDecimals[assetA]; - if (!assetADecimals) throw new Error(`Decimals for asset '${assetA}' not found`); + if (assetADecimals === undefined) throw new Error(`Decimals for asset '${assetA}' not found`); const assetBDecimals = assetToDecimals[assetB]; - if (!assetBDecimals) throw new Error(`Decimals for asset '${assetB}' not found`); + if (assetBDecimals === undefined) throw new Error(`Decimals for asset '${assetB}' not found`); const poolsConfig = await simpleFetch(this.orionUnit.orionBlockchain.getPoolsConfig)(); const pool = poolsConfig.pools[poolName]; diff --git a/src/OrionUnit/index.ts b/src/OrionUnit/index.ts index 6aadd84..d18bdc8 100644 --- a/src/OrionUnit/index.ts +++ b/src/OrionUnit/index.ts @@ -6,7 +6,7 @@ import type { SupportedChainId, VerboseOrionUnitConfig } from '../types'; import Exchange from './Exchange'; import FarmingManager from './FarmingManager'; import { chains } from '../config'; -import { networkCodes } from '../constants'; +import { type networkCodes } from '../constants'; // type KnownConfig = { // env: string; diff --git a/src/__tests__/basic.test.ts b/src/__tests__/basic.test.ts index 54abae1..aabb327 100644 --- a/src/__tests__/basic.test.ts +++ b/src/__tests__/basic.test.ts @@ -8,14 +8,23 @@ import express from 'express'; import WebSocket from 'ws'; import http from 'http'; import httpToWS from '../utils/httpToWS'; +import { + createHttpTerminator, +} from 'http-terminator'; + +jest.setTimeout(10000); const createServer = (externalHost: string) => { const app = express(); const server = http.createServer(app); + + const httpTerminator = createHttpTerminator({ server }); const wss = new WebSocket.Server({ server }); let externalWs: WebSocket | null = null; + wss.on('connection', (ws, req) => { + if (req.url === undefined) throw new Error('req.url is undefined'); const targetUrl = httpToWS(`${externalHost}${req.url}`); externalWs = new WebSocket(targetUrl); @@ -32,33 +41,40 @@ const createServer = (externalHost: string) => { app.get( '*', - async (req, res) => { - const routeFromURL = req.url; - try { - const targetUrl = `${externalHost}${routeFromURL}`; - const response = await fetch(targetUrl); - const text = await response.text(); - res.send(text); - } catch (error) { - res.status(500).send({ - error: 'Failed to retrieve data from external resource' - }); - } + (req, res) => { + (async () => { + const routeFromURL = req.url; + try { + const targetUrl = `${externalHost}${routeFromURL}`; + const response = await fetch(targetUrl); + const text = await response.text(); + res.send(text); + } catch (error) { + res.status(500).send({ + error: 'Failed to retrieve data from external resource' + }); + } + })().catch(console.error) }); server.listen(0); + const address = server.address(); if (typeof address === 'string') { throw new Error(`Server address is a string: ${address}`); } + const closeWS = () => new Promise((resolve) => { + wss.close(resolve); + }); return { port: address?.port, - close: () => new Promise((resolve) => { + terminate: async () => { externalWs?.close(); - server.close(resolve); - }), + await closeWS(); + await httpTerminator.terminate(); + } } } @@ -137,6 +153,10 @@ describe('Orion', () => { const server1 = createServer('https://trade.orionprotocol.io'); const server2 = createServer('https://trade.orionprotocol.io'); + if (server0.port === undefined || server1.port === undefined || server2.port === undefined) { + throw new Error('Server port is undefined'); + } + const orionBlockchainAPI = `http://localhost:${server0.port}`; const orionAggregatorAPI = `http://localhost:${server1.port}`; const orionPriceFeedAPI = `http://localhost:${server2.port}`; @@ -165,7 +185,7 @@ describe('Orion', () => { } }); - const orionUnit = orion.unitsArray[0]; + const [orionUnit] = orion.unitsArray; if (!orionUnit) { throw new Error('Orion unit is not defined'); } @@ -197,10 +217,6 @@ describe('Orion', () => { expect(priceData).toBeDefined(); const allTickersDone = await new Promise((resolve, reject) => { - const timeout = setTimeout(() => { - reject(new Error('Timeout')); - }, 10000); - const { unsubscribe } = orionUnit.priceFeed.ws.subscribe( 'allTickers', { @@ -211,12 +227,16 @@ describe('Orion', () => { } } ) + const timeout = setTimeout(() => { + unsubscribe(); + reject(new Error(`Timeout: ${orionUnit.priceFeed.wsUrl}`)); + }, 10000); }); expect(allTickersDone).toBe(true); - await server0.close(); - await server1.close(); - await server2.close(); + await server0.terminate(); + await server1.terminate(); + await server2.terminate(); }); test('Init Orion testing with overrides', () => { diff --git a/src/constants/exchangesMap.ts b/src/constants/exchangesMap.ts index da95748..40dabfe 100644 --- a/src/constants/exchangesMap.ts +++ b/src/constants/exchangesMap.ts @@ -1,4 +1,4 @@ -import exchanges from './exchanges'; +import type exchanges from './exchanges'; const mapping: Record< typeof exchanges[number], diff --git a/src/crypt/getDomainData.ts b/src/crypt/getDomainData.ts index ed459e7..d43c75e 100644 --- a/src/crypt/getDomainData.ts +++ b/src/crypt/getDomainData.ts @@ -1,4 +1,4 @@ -import { SupportedChainId } from '../types'; +import { type SupportedChainId } from '../types'; import eip712DomainData from '../config/eip712DomainData.json'; import eip712DomainSchema from '../config/schemas/eip712DomainSchema'; diff --git a/src/crypt/hashCFDOrder.ts b/src/crypt/hashCFDOrder.ts index 0ee0654..099d217 100644 --- a/src/crypt/hashCFDOrder.ts +++ b/src/crypt/hashCFDOrder.ts @@ -1,5 +1,5 @@ import { ethers } from 'ethers'; -import { CFDOrder } from '../types'; +import { type CFDOrder } from '../types'; const hashCFDOrder = (order: CFDOrder) => ethers.utils.solidityKeccak256( [ @@ -24,7 +24,7 @@ const hashCFDOrder = (order: CFDOrder) => ethers.utils.solidityKeccak256( order.matcherFee, order.nonce, order.expiration, - order.buySide ? '0x01' : '0x00', + order.buySide === 1 ? '0x01' : '0x00', ], ); diff --git a/src/crypt/hashOrder.ts b/src/crypt/hashOrder.ts index 1521532..7d6cdeb 100644 --- a/src/crypt/hashOrder.ts +++ b/src/crypt/hashOrder.ts @@ -1,5 +1,5 @@ import { ethers } from 'ethers'; -import { Order } from '../types'; +import { type Order } from '../types'; const hashOrder = (order: Order) => ethers.utils.solidityKeccak256( [ @@ -28,7 +28,7 @@ const hashOrder = (order: Order) => ethers.utils.solidityKeccak256( order.matcherFee, order.nonce, order.expiration, - order.buySide ? '0x01' : '0x00', + order.buySide === 1 ? '0x01' : '0x00', ], ); diff --git a/src/crypt/signCFDOrder.ts b/src/crypt/signCFDOrder.ts index 8ac346f..554ee39 100644 --- a/src/crypt/signCFDOrder.ts +++ b/src/crypt/signCFDOrder.ts @@ -1,10 +1,9 @@ -/* eslint-disable no-underscore-dangle */ -import { TypedDataSigner } from '@ethersproject/abstract-signer'; +import { type TypedDataSigner } from '@ethersproject/abstract-signer'; import BigNumber from 'bignumber.js'; -import { ethers } from 'ethers'; +import { type ethers } from 'ethers'; import { joinSignature, splitSignature } from 'ethers/lib/utils'; import { INTERNAL_ORION_PRECISION } from '../constants'; -import { CFDOrder, SignedCFDOrder, SupportedChainId } from '../types'; +import { type CFDOrder, type SignedCFDOrder, type SupportedChainId } from '../types'; import normalizeNumber from '../utils/normalizeNumber'; import getDomainData from './getDomainData'; import signCFDOrderPersonal from './signCFDOrderPersonal'; @@ -69,7 +68,7 @@ export const signCFDOrder = async ( // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1" const fixedSignature = joinSignature(splitSignature(signature)); - if (!fixedSignature) throw new Error("Can't sign order"); + // if (!fixedSignature) throw new Error("Can't sign order"); const signedOrder: SignedCFDOrder = { ...order, diff --git a/src/crypt/signCFDOrderPersonal.ts b/src/crypt/signCFDOrderPersonal.ts index fad91c0..d47889a 100644 --- a/src/crypt/signCFDOrderPersonal.ts +++ b/src/crypt/signCFDOrderPersonal.ts @@ -1,5 +1,5 @@ import { ethers } from 'ethers'; -import { CFDOrder } from '../types'; +import { type CFDOrder } from '../types'; const { arrayify, joinSignature, splitSignature } = ethers.utils; diff --git a/src/crypt/signCancelOrder.ts b/src/crypt/signCancelOrder.ts index 098b7e9..10cb6a6 100644 --- a/src/crypt/signCancelOrder.ts +++ b/src/crypt/signCancelOrder.ts @@ -1,9 +1,8 @@ -/* eslint-disable no-underscore-dangle */ -import { TypedDataSigner } from '@ethersproject/abstract-signer'; -import { ethers } from 'ethers'; +import { type TypedDataSigner } from '@ethersproject/abstract-signer'; +import { type ethers } from 'ethers'; import { joinSignature, splitSignature } from 'ethers/lib/utils'; import CANCEL_ORDER_TYPES from '../constants/cancelOrderTypes'; -import { CancelOrderRequest, SignedCancelOrderRequest, SupportedChainId } from '../types'; +import { type CancelOrderRequest, type SignedCancelOrderRequest, type SupportedChainId } from '../types'; import getDomainData from './getDomainData'; import signCancelOrderPersonal from './signCancelOrderPersonal'; @@ -37,7 +36,7 @@ const signCancelOrder = async ( // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1" const fixedSignature = joinSignature(splitSignature(signature)); - if (!fixedSignature) throw new Error("Can't sign order cancel"); + // if (!fixedSignature) throw new Error("Can't sign order cancel"); const signedCancelOrderReqeust: SignedCancelOrderRequest = { ...cancelOrderRequest, diff --git a/src/crypt/signCancelOrderPersonal.ts b/src/crypt/signCancelOrderPersonal.ts index b06512f..f3b3855 100644 --- a/src/crypt/signCancelOrderPersonal.ts +++ b/src/crypt/signCancelOrderPersonal.ts @@ -1,6 +1,6 @@ import { ethers } from 'ethers'; import { arrayify, joinSignature, splitSignature } from 'ethers/lib/utils'; -import { CancelOrderRequest } from '../types'; +import { type CancelOrderRequest } from '../types'; const signCancelOrderPersonal = async ( cancelOrderRequest: CancelOrderRequest, diff --git a/src/crypt/signOrder.ts b/src/crypt/signOrder.ts index 9bd9c88..983e480 100644 --- a/src/crypt/signOrder.ts +++ b/src/crypt/signOrder.ts @@ -1,11 +1,10 @@ -/* eslint-disable no-underscore-dangle */ -import { TypedDataSigner } from '@ethersproject/abstract-signer'; +import { type TypedDataSigner } from '@ethersproject/abstract-signer'; import BigNumber from 'bignumber.js'; -import { ethers } from 'ethers'; +import { type ethers } from 'ethers'; import { joinSignature, splitSignature } from 'ethers/lib/utils'; import { INTERNAL_ORION_PRECISION } from '../constants'; import ORDER_TYPES from '../constants/orderTypes'; -import { Order, SignedOrder, SupportedChainId } from '../types'; +import { type Order, type SignedOrder, type SupportedChainId } from '../types'; import normalizeNumber from '../utils/normalizeNumber'; import getDomainData from './getDomainData'; import hashOrder from './hashOrder'; @@ -74,7 +73,7 @@ export const signOrder = async ( // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1" const fixedSignature = joinSignature(splitSignature(signature)); - if (!fixedSignature) throw new Error("Can't sign order"); + // if (!fixedSignature) throw new Error("Can't sign order"); const signedOrder: SignedOrder = { ...order, diff --git a/src/crypt/signOrderPersonal.ts b/src/crypt/signOrderPersonal.ts index 9c08f6e..35efe4c 100644 --- a/src/crypt/signOrderPersonal.ts +++ b/src/crypt/signOrderPersonal.ts @@ -1,5 +1,5 @@ import { ethers } from 'ethers'; -import { Order } from '../types'; +import { type Order } from '../types'; const { arrayify, joinSignature, splitSignature } = ethers.utils; diff --git a/src/fetchWithValidation.ts b/src/fetchWithValidation.ts index 795df5f..8a68030 100644 --- a/src/fetchWithValidation.ts +++ b/src/fetchWithValidation.ts @@ -1,4 +1,4 @@ -import { Schema, z } from 'zod'; +import { type Schema, type z } from 'zod'; import fetch from 'isomorphic-unfetch'; import { @@ -26,7 +26,7 @@ export default async function fetchWithValidation { url.searchParams.append('exchanges', exchange); @@ -241,7 +241,7 @@ class OrionAggregator { url.searchParams.append('exchanges', exchanges); } } - if (instantSettlement) { + if (instantSettlement !== undefined && instantSettlement) { url.searchParams.append('instantSettlement', 'true'); } diff --git a/src/services/OrionAggregator/ws/index.ts b/src/services/OrionAggregator/ws/index.ts index d90a42e..ebcdbb0 100644 --- a/src/services/OrionAggregator/ws/index.ts +++ b/src/services/OrionAggregator/ws/index.ts @@ -10,12 +10,12 @@ import { } from './schemas'; import UnsubscriptionType from './UnsubscriptionType'; import { - SwapInfoBase, AssetPairUpdate, OrderbookItem, Balance, - Exchange, CFDBalance, SwapInfo, FuturesTradeInfo, + type SwapInfoBase, type AssetPairUpdate, type OrderbookItem, + type Balance, type Exchange, type CFDBalance, type FuturesTradeInfo, type SwapInfo, } from '../../../types'; import unsubscriptionDoneSchema from './schemas/unsubscriptionDoneSchema'; import assetPairConfigSchema from './schemas/assetPairConfigSchema'; -import { fullOrderSchema, orderUpdateSchema } from './schemas/addressUpdateSchema'; +import { type fullOrderSchema, type orderUpdateSchema } from './schemas/addressUpdateSchema'; import cfdAddressUpdateSchema from './schemas/cfdAddressUpdateSchema'; import futuresTradeInfoSchema from './schemas/futuresTradeInfoSchema'; // import errorSchema from './schemas/errorSchema'; @@ -25,108 +25,108 @@ const UNSUBSCRIBE = 'u'; // https://github.com/orionprotocol/orion-aggregator/tree/feature/OP-1752-symmetric-swap#swap-info-subscribe type SwapSubscriptionRequest = { // d: string, // swap request UUID, set by client side - i: string, // asset in - o: string, // asset out + i: string // asset in + o: string // asset out a: number // amount IN/OUT - es?: Exchange[] | 'cex' | 'pools', // exchange list of all cex or all pools (ORION_POOL, UNISWAP, PANCAKESWAP etc) - e?: boolean; // is amount IN? Value `false` means a = amount OUT, `true` if omitted - is?: boolean; // instant settlement + es?: Exchange[] | 'cex' | 'pools' // exchange list of all cex or all pools (ORION_POOL, UNISWAP, PANCAKESWAP etc) + e?: boolean // is amount IN? Value `false` means a = amount OUT, `true` if omitted + is?: boolean // instant settlement } type BrokerTradableAtomicSwapBalanceSubscription = { - callback: (balances: Partial>) => void, + callback: (balances: Partial>) => void } type PairsConfigSubscription = { callback: ({ kind, data }: { - kind: 'initial' | 'update', - data: Partial>, - }) => void, + kind: 'initial' | 'update' + data: Partial> + }) => void } type PairConfigSubscription = { - payload: string, + payload: string callback: ({ kind, data }: { - kind: 'initial' | 'update', - data: AssetPairUpdate, - }) => void, + kind: 'initial' | 'update' + data: AssetPairUpdate + }) => void } type AggregatedOrderbookSubscription = { - payload: string, + payload: string callback: ( asks: OrderbookItem[], bids: OrderbookItem[], pair: string - ) => void, + ) => void } type SwapInfoSubscription = { - payload: SwapSubscriptionRequest, - callback: (swapInfo: SwapInfo) => void, + payload: SwapSubscriptionRequest + callback: (swapInfo: SwapInfo) => void } type FuturesTradeInfoSubscription = { payload: { - s: string, - i: string, - a: number, - p?: number, - }, - callback: (futuresTradeInfo: FuturesTradeInfo) => void, + s: string + i: string + a: number + p?: number + } + callback: (futuresTradeInfo: FuturesTradeInfo) => void } type AddressUpdateUpdate = { - kind: 'update', + kind: 'update' balances: Partial< - Record< - string, - Balance - > - >, + Record< + string, + Balance + > + > order?: z.infer | z.infer } type AddressUpdateInitial = { - kind: 'initial', + kind: 'initial' balances: Partial< - Record< - string, - Balance - > - >, - orders?: z.infer[] // The field is not defined if the user has no orders + Record< + string, + Balance + > + > + orders?: Array> // The field is not defined if the user has no orders } type CfdAddressUpdateUpdate = { - kind: 'update', - balances?: CFDBalance[], + kind: 'update' + balances?: CFDBalance[] order?: z.infer | z.infer } type CfdAddressUpdateInitial = { - kind: 'initial', - balances: CFDBalance[], - orders?: z.infer[] // The field is not defined if the user has no orders + kind: 'initial' + balances: CFDBalance[] + orders?: Array> // The field is not defined if the user has no orders } type AddressUpdateSubscription = { - payload: string, - callback: (data: AddressUpdateUpdate | AddressUpdateInitial) => void, + payload: string + callback: (data: AddressUpdateUpdate | AddressUpdateInitial) => void } type CfdAddressUpdateSubscription = { - payload: string, - callback: (data: CfdAddressUpdateUpdate | CfdAddressUpdateInitial) => void, + payload: string + callback: (data: CfdAddressUpdateUpdate | CfdAddressUpdateInitial) => void } type Subscription = { - [SubscriptionType.ADDRESS_UPDATES_SUBSCRIBE]: AddressUpdateSubscription, - [SubscriptionType.CFD_ADDRESS_UPDATES_SUBSCRIBE]: CfdAddressUpdateSubscription, - [SubscriptionType.AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE]: AggregatedOrderbookSubscription, - [SubscriptionType.ASSET_PAIRS_CONFIG_UPDATES_SUBSCRIBE]: PairsConfigSubscription, - [SubscriptionType.ASSET_PAIR_CONFIG_UPDATES_SUBSCRIBE]: PairConfigSubscription, - [SubscriptionType.BROKER_TRADABLE_ATOMIC_SWAP_ASSETS_BALANCE_UPDATES_SUBSCRIBE]: BrokerTradableAtomicSwapBalanceSubscription, + [SubscriptionType.ADDRESS_UPDATES_SUBSCRIBE]: AddressUpdateSubscription + [SubscriptionType.CFD_ADDRESS_UPDATES_SUBSCRIBE]: CfdAddressUpdateSubscription + [SubscriptionType.AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE]: AggregatedOrderbookSubscription + [SubscriptionType.ASSET_PAIRS_CONFIG_UPDATES_SUBSCRIBE]: PairsConfigSubscription + [SubscriptionType.ASSET_PAIR_CONFIG_UPDATES_SUBSCRIBE]: PairConfigSubscription + [SubscriptionType.BROKER_TRADABLE_ATOMIC_SWAP_ASSETS_BALANCE_UPDATES_SUBSCRIBE]: BrokerTradableAtomicSwapBalanceSubscription [SubscriptionType.SWAP_SUBSCRIBE]: SwapInfoSubscription [SubscriptionType.FUTURES_TRADE_INFO_SUBSCRIBE]: FuturesTradeInfoSubscription } @@ -145,14 +145,14 @@ type BufferLike = | Uint8Array | ArrayBuffer | SharedArrayBuffer - | ReadonlyArray - | ReadonlyArray - | { valueOf(): ArrayBuffer } - | { valueOf(): SharedArrayBuffer } - | { valueOf(): Uint8Array } - | { valueOf(): ReadonlyArray } - | { valueOf(): string } - | { [Symbol.toPrimitive](hint: string): string }; + | readonly unknown[] + | readonly number[] + | { valueOf: () => ArrayBuffer } + | { valueOf: () => SharedArrayBuffer } + | { valueOf: () => Uint8Array } + | { valueOf: () => readonly number[] } + | { valueOf: () => string } + | { [Symbol.toPrimitive]: (hint: string) => string }; const isSubType = (subType: string): subType is keyof Subscription => Object.values(SubscriptionType).some((t) => t === subType); class OrionAggregatorWS { @@ -339,8 +339,9 @@ class OrionAggregatorWS { }; this.ws.onmessage = (e) => { const { data } = e; - this.logger?.(`OrionAggregatorWS: received message: ${e.data.toString()}`); - const rawJson: unknown = JSON.parse(data.toString()); + if (typeof data !== 'string') throw new Error('OrionAggregatorWS: received non-string message'); + this.logger?.(`OrionAggregatorWS: received message: ${data}`); + const rawJson: unknown = JSON.parse(data); const messageSchema = z.union([ initMessageSchema, @@ -385,7 +386,7 @@ class OrionAggregatorWS { path: json.ps, exchanges: json.e, poolOptimal: json.po, - ...json.oi && { + ...(json.oi) && { orderInfo: { pair: json.oi.p, side: json.oi.s, @@ -511,8 +512,8 @@ class OrionAggregatorWS { case MessageType.CFD_ADDRESS_UPDATE: switch (json.k) { // message kind case 'i': { // initial - const fullOrders = json.o - ? json.o.reduce[]>((prev, o) => { + const fullOrders = (json.o) + ? json.o.reduce>>((prev, o) => { prev.push(o); return prev; @@ -524,7 +525,7 @@ class OrionAggregatorWS { ]?.[json.id]?.callback({ kind: 'initial', orders: fullOrders, - balances: json.b ?? [], + balances: json.b, }); } break; @@ -549,7 +550,7 @@ class OrionAggregatorWS { } break; case MessageType.ADDRESS_UPDATE: { - const balances = json.b + const balances = (json.b) ? Object.entries(json.b) .reduce>>((prev, [asset, assetBalances]) => { if (!assetBalances) return prev; @@ -565,7 +566,7 @@ class OrionAggregatorWS { switch (json.k) { // message kind case 'i': { // initial const fullOrders = json.o - ? json.o.reduce[]>((prev, o) => { + ? json.o.reduce>>((prev, o) => { prev.push(o); return prev; diff --git a/src/services/OrionAnalytics/index.ts b/src/services/OrionAnalytics/index.ts index 684d61e..374fe5a 100644 --- a/src/services/OrionAnalytics/index.ts +++ b/src/services/OrionAnalytics/index.ts @@ -2,7 +2,7 @@ import fetchWithValidation from '../../fetchWithValidation'; import overviewSchema from './schemas/overviewSchema'; export default class OrionAnalytics { - private apiUrl: string; + private readonly apiUrl: string; constructor(apiUrl: string) { this.apiUrl = apiUrl; diff --git a/src/services/OrionBlockchain/index.ts b/src/services/OrionBlockchain/index.ts index 415e0e0..3343f2a 100644 --- a/src/services/OrionBlockchain/index.ts +++ b/src/services/OrionBlockchain/index.ts @@ -3,63 +3,63 @@ import fetchWithValidation from '../../fetchWithValidation'; import { IDOSchema, atomicHistorySchema, poolsConfigSchema, poolsInfoSchema, infoSchema, historySchema, - addPoolSchema, adminPoolsListSchema, adminPoolSchema, + type addPoolSchema, adminPoolsListSchema, adminPoolSchema, atomicSummarySchema, poolsLpAndStakedSchema, userVotesSchema, userEarnedSchema, - PairStatusEnum, + type PairStatusEnum, pairStatusSchema, cfdContractsSchema, cfdHistorySchema, } from './schemas'; -import redeemOrderSchema from '../OrionAggregator/schemas/redeemOrderSchema'; +import type redeemOrderSchema from '../OrionAggregator/schemas/redeemOrderSchema'; import { sourceAtomicHistorySchema, targetAtomicHistorySchema } from './schemas/atomicHistorySchema'; import { makePartial } from '../../utils'; -import { networkCodes } from '../../constants'; +import { type networkCodes } from '../../constants'; -interface IAdminAuthHeaders { - auth: string; +type IAdminAuthHeaders = { + auth: string [key: string]: string } -export interface IEditPool { - tokenAIcon?: string; - tokenBIcon?: string; - symbol?: string; - status: PairStatusEnum; - minQty?: number; - tokenASymbol?: string; - tokenBSymbol?: string; - tokensReversed?: boolean; +export type IEditPool = { + tokenAIcon?: string + tokenBIcon?: string + symbol?: string + status: PairStatusEnum + minQty?: number + tokenASymbol?: string + tokenBSymbol?: string + tokensReversed?: boolean } type AtomicSwapHistoryBaseQuery = { limit?: number - sender?: string, - receiver?: string, - used?: 0 | 1, - page?: number, - sourceNetworkCode?: typeof networkCodes[number], -} + sender?: string + receiver?: string + used?: 0 | 1 + page?: number + sourceNetworkCode?: typeof networkCodes[number] +} & Partial> type AtomicSwapHistorySourceQuery = AtomicSwapHistoryBaseQuery & { - type?: 'source', - expiredLock?: 0 | 1, - state?: 'LOCKED' | 'CLAIMED' |'REFUNDED', + type?: 'source' + expiredLock?: 0 | 1 + state?: 'LOCKED' | 'CLAIMED' | 'REFUNDED' } type AtomicSwapHistoryTargetQuery = AtomicSwapHistoryBaseQuery & { - type?: 'target', - expiredRedeem?: 0 | 1, - state?: 'REDEEMED' | 'BEFORE-REDEEM', + type?: 'target' + expiredRedeem?: 0 | 1 + state?: 'REDEEMED' | 'BEFORE-REDEEM' } type CfdHistoryQuery = { - instrument?: string, - page?: number, - limit?: number, -} + instrument?: string + page?: number + limit?: number +} & Partial> class OrionBlockchain { private readonly apiUrl: string; @@ -110,12 +110,12 @@ class OrionBlockchain { return `${this.apiUrl}/`; } - private getSummaryRedeem = (brokerAddress: string, unshifted?: 1 | 0, sourceNetworkCode?: typeof networkCodes[number]) => { + private readonly getSummaryRedeem = (brokerAddress: string, unshifted?: 1 | 0, sourceNetworkCode?: typeof networkCodes[number]) => { const url = new URL(`${this.apiUrl}/api/atomic/summary-redeem/${brokerAddress}`); - if (unshifted) { + if (unshifted !== undefined && unshifted === 1) { url.searchParams.append('unshifted', unshifted.toString()); } - if (sourceNetworkCode) { + if (sourceNetworkCode !== undefined) { url.searchParams.append('sourceNetworkCode', sourceNetworkCode); } return fetchWithValidation( @@ -124,12 +124,12 @@ class OrionBlockchain { ); }; - private getSummaryClaim = (brokerAddress: string) => fetchWithValidation( + private readonly getSummaryClaim = (brokerAddress: string) => fetchWithValidation( `${this.apiUrl}/api/atomic/summary-claim/${brokerAddress}`, atomicSummarySchema, ); - private getQueueLength = () => fetchWithValidation( + private readonly getQueueLength = () => fetchWithValidation( `${this.apiUrl}/api/queueLength`, z.number().int(), ); @@ -357,7 +357,10 @@ class OrionBlockchain { const url = new URL(`${this.apiUrl}/api/atomic/history/`); Object.entries(query) - .forEach(([key, value]) => url.searchParams.append(key, value.toString())); + .forEach(([key, value]) => { + if (value === undefined) throw new Error('Value must be defined'); + url.searchParams.append(key, value.toString()); + }); return fetchWithValidation(url.toString(), atomicHistorySchema); }; @@ -366,9 +369,12 @@ class OrionBlockchain { const url = new URL(`${this.apiUrl}/api/atomic/history/`); Object.entries(query) - .forEach(([key, value]) => url.searchParams.append(key, value.toString())); + .forEach(([key, value]) => { + if (value === undefined) throw new Error('Value must be defined'); + url.searchParams.append(key, value.toString()); + }); - if (!query.type) url.searchParams.append('type', 'source'); + if (query.type !== undefined) url.searchParams.append('type', 'source'); return fetchWithValidation(url.toString(), sourceAtomicHistorySchema); }; @@ -377,9 +383,12 @@ class OrionBlockchain { const url = new URL(`${this.apiUrl}/api/atomic/history/`); Object.entries(query) - .forEach(([key, value]) => url.searchParams.append(key, value.toString())); + .forEach(([key, value]) => { + if (value === undefined) throw new Error('Value must be defined'); + url.searchParams.append(key, value.toString()); + }); - if (!query.type) url.searchParams.append('type', 'target'); + if (query.type !== undefined) url.searchParams.append('type', 'target'); return fetchWithValidation(url.toString(), targetAtomicHistorySchema); }; @@ -406,7 +415,10 @@ class OrionBlockchain { const url = new URL(`${this.apiUrl}/api/cfd/deposit-withdraw/${address}`); Object.entries(query) - .forEach(([key, value]) => url.searchParams.append(key, value.toString())); + .forEach(([key, value]) => { + if (value === undefined) throw new Error('Value must be defined'); + url.searchParams.append(key, value.toString()); + }); return fetchWithValidation(url.toString(), cfdHistorySchema); }; diff --git a/src/services/PriceFeed/index.ts b/src/services/PriceFeed/index.ts index cdf694d..2a0e5bd 100644 --- a/src/services/PriceFeed/index.ts +++ b/src/services/PriceFeed/index.ts @@ -1,11 +1,11 @@ import fetchWithValidation from '../../fetchWithValidation'; -import { Exchange } from '../../types'; +import { type Exchange } from '../../types'; import { statisticsOverviewSchema, topPairsStatisticsSchema } from './schemas'; import candlesSchema from './schemas/candlesSchema'; import { PriceFeedWS } from './ws'; class PriceFeed { - private apiUrl: string; + private readonly apiUrl: string; readonly ws: PriceFeedWS; diff --git a/src/services/PriceFeed/ws/PriceFeedSubscription.ts b/src/services/PriceFeed/ws/PriceFeedSubscription.ts index 795e318..4ed9773 100644 --- a/src/services/PriceFeed/ws/PriceFeedSubscription.ts +++ b/src/services/PriceFeed/ws/PriceFeedSubscription.ts @@ -6,12 +6,12 @@ import { tickerInfoSchema, candleSchema } from './schemas'; import priceSchema from './schemas/priceSchema'; type TickerInfo = { - pairName: string; - lastPrice: string; - openPrice: string; - highPrice: string; - lowPrice: string; - volume24h: string; + pairName: string + lastPrice: string + openPrice: string + highPrice: string + lowPrice: string + volume24h: string } const allTickersSchema = z.unknown().array() @@ -57,11 +57,11 @@ export type Subscription< Schema = z.infer > = typeof subscriptions[T] extends { payload: true } ? { - callback: (data: Schema) => void, - payload: string, -} : { - callback: (data: Schema) => void, -} + callback: (data: Schema) => void + payload: string + } : { + callback: (data: Schema) => void + } export default class PriceFeedSubscription { public readonly id: string; @@ -104,16 +104,23 @@ export default class PriceFeedSubscription { - if (e.data === 'pong') return; - const json: unknown = JSON.parse(e.data.toString()); + const { data } = e; + + // const isBufferArray = Array.isArray(data); + // const isArrayBuffer = data instanceof ArrayBuffer; + const isBuffer = Buffer.isBuffer(data); + if (!isBuffer) throw new Error('Not a buffer'); + const dataString = data.toString(); + if (dataString === 'pong') return; + const json: unknown = JSON.parse(dataString); const subscription = subscriptions[type]; const parseResult = subscription.schema.safeParse(json); - if (parseResult.success === false) { + if (!parseResult.success) { const errorsMessage = parseResult.error.errors.map((error) => `[${error.path.join('.')}] ${error.message}`).join(', '); - throw new Error(`Can't recognize PriceFeed "${type}" subscription message "${e.data.toString()}": ${errorsMessage}`); + throw new Error(`Can't recognize PriceFeed "${type}" subscription message "${dataString}": ${errorsMessage}`); } this.callback(parseResult.data); }; diff --git a/src/services/PriceFeed/ws/index.ts b/src/services/PriceFeed/ws/index.ts index 4cbaec2..2eff423 100644 --- a/src/services/PriceFeed/ws/index.ts +++ b/src/services/PriceFeed/ws/index.ts @@ -1,4 +1,4 @@ -import PriceFeedSubscription, { SubscriptionType, Subscription } from './PriceFeedSubscription'; +import PriceFeedSubscription, { type SubscriptionType, type Subscription } from './PriceFeedSubscription'; export * as schemas from './schemas'; export class PriceFeedWS { @@ -11,7 +11,7 @@ export class PriceFeedWS { >; }> = {}; - private url: string; + private readonly url: string; constructor(url: string) { this.url = url; @@ -36,7 +36,7 @@ export class PriceFeedWS { return { type: sub.type, id: sub.id, - unsubscribe: () => this.unsubscribe(sub.type, sub.id), + unsubscribe: () => { this.unsubscribe(sub.type, sub.id); }, }; } diff --git a/src/services/ReferralSystem/index.ts b/src/services/ReferralSystem/index.ts index 1c86c64..3a6c81e 100644 --- a/src/services/ReferralSystem/index.ts +++ b/src/services/ReferralSystem/index.ts @@ -6,21 +6,21 @@ import globalAnalyticsSchema from './schemas/globalAnalyticsSchema'; import linkSchema from './schemas/linkSchema'; type CreateLinkPayloadType = { - referer: string; - link_option: number; -}; + referer: string + link_option: number +} type SubscribePayloadType = { - ref_target: string; - referral: string; + ref_target: string + referral: string } type SignatureType = { - signature: string; -}; + signature: string +} class ReferralSystem { - private apiUrl: string; + private readonly apiUrl: string; get api() { return this.apiUrl; diff --git a/src/simpleFetch.ts b/src/simpleFetch.ts index 82e4fc4..ef36606 100644 --- a/src/simpleFetch.ts +++ b/src/simpleFetch.ts @@ -1,4 +1,4 @@ -import { Schema, z } from 'zod'; +import { type Schema, type z } from 'zod'; import fetchWithValidation from './fetchWithValidation'; // https://stackoverflow.com/a/64919133 diff --git a/src/types.ts b/src/types.ts index 5c223aa..24c5836 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,117 +1,117 @@ -import BigNumber from 'bignumber.js'; -import exchanges from './constants/exchanges'; -import subOrderStatuses from './constants/subOrderStatuses'; -import positionStatuses from './constants/positionStatuses'; +import type BigNumber from 'bignumber.js'; +import type exchanges from './constants/exchanges'; +import type subOrderStatuses from './constants/subOrderStatuses'; +import type positionStatuses from './constants/positionStatuses'; export type DeepPartial = T extends object ? { [P in keyof T]?: DeepPartial; } : T; export type AssetPairUpdate = { - minQty: number, - pricePrecision: number, + minQty: number + pricePrecision: number } export type SubOrder = { - pair: string, - exchange: string, - id: number, - amount: number, - settledAmount: number, - price: number, - status: typeof subOrderStatuses[number], - side: 'BUY' | 'SELL', + pair: string + exchange: string + id: number + amount: number + settledAmount: number + price: number + status: typeof subOrderStatuses[number] + side: 'BUY' | 'SELL' subOrdQty: number } export type Balance = { - tradable: string, - reserved: string, - contract: string, - wallet: string, - allowance: string, + tradable: string + reserved: string + contract: string + wallet: string + allowance: string } export type PositionStatus = typeof positionStatuses[number]; export type CFDBalance = { - instrument: string, - balance: string, - profitLoss: string, - fundingRate: string, - equity: string, - position: string, - currentPrice: string, - positionPrice: string, - reserves: string, - margin: string, - marginUSD: string, - freeMarginUSD: string, - availableWithdrawBalance: string, - leverage: string, - status: PositionStatus, + instrument: string + balance: string + profitLoss: string + fundingRate: string + equity: string + position: string + currentPrice: string + positionPrice: string + reserves: string + margin: string + marginUSD: string + freeMarginUSD: string + availableWithdrawBalance: string + leverage: string + status: PositionStatus } -export interface Order { - senderAddress: string; // address - matcherAddress: string; // address - baseAsset: string; // address - quoteAsset: string; // address - matcherFeeAsset: string; // address - amount: number; // uint64 - price: number; // uint64 - matcherFee: number; // uint64 - nonce: number; // uint64 - expiration: number; // uint64 - buySide: number; // uint8, 1=buy, 0=sell - isPersonalSign: boolean; // bool +export type Order = { + senderAddress: string // address + matcherAddress: string // address + baseAsset: string // address + quoteAsset: string // address + matcherFeeAsset: string // address + amount: number // uint64 + price: number // uint64 + matcherFee: number // uint64 + nonce: number // uint64 + expiration: number // uint64 + buySide: 0 | 1 // uint8, 1=buy, 0=sell + isPersonalSign: boolean // bool } -export interface CFDOrder { - senderAddress: string; // address - matcherAddress: string; // address - instrumentAddress: string; // address - amount: number; // uint64 - price: number; // uint64 - matcherFee: number; // uint64 - nonce: number; // uint64 - expiration: number; // uint64 - buySide: number; // uint8, 1=buy, 0=sell - isPersonalSign: boolean; // bool +export type CFDOrder = { + senderAddress: string // address + matcherAddress: string // address + instrumentAddress: string // address + amount: number // uint64 + price: number // uint64 + matcherFee: number // uint64 + nonce: number // uint64 + expiration: number // uint64 + buySide: 0 | 1 // uint8, 1=buy, 0=sell + isPersonalSign: boolean // bool } -export interface SignedCFDOrder extends CFDOrder { - id: string; // hash of Order (it's not part of order structure in smart-contract) - signature: string; // bytes +export type SignedCFDOrder = { + id: string // hash of Order (it's not part of order structure in smart-contract) + signature: string // bytes +} & CFDOrder + +export type SignedOrder = { + id: string // hash of Order (it's not part of order structure in smart-contract) + signature: string // bytes + needWithdraw?: boolean // bool (not supported yet by smart-contract) +} & Order + +export type CancelOrderRequest = { + id: number | string + senderAddress: string + isPersonalSign: boolean } -export interface SignedOrder extends Order { - id: string; // hash of Order (it's not part of order structure in smart-contract) - signature: string; // bytes - needWithdraw?: boolean; // bool (not supported yet by smart-contract) -} +export type SignedCancelOrderRequest = { + id: number | string + senderAddress: string + signature: string +} & CancelOrderRequest -export interface CancelOrderRequest { - id: number | string; - senderAddress: string; - isPersonalSign: boolean; -} - -export interface SignedCancelOrderRequest extends CancelOrderRequest { - id: number | string; - senderAddress: string; - signature: string; -} - -export interface Pair { - name: string; - baseCurrency: string; - quoteCurrency: string; - lastPrice: string; - openPrice: string; - change24h: string; - high: string; - low: string; - vol24h: string; +export type Pair = { + name: string + baseCurrency: string + quoteCurrency: string + lastPrice: string + openPrice: string + change24h: string + high: string + low: string + vol24h: string } export enum SupportedChainId { @@ -135,114 +135,114 @@ const balanceTypes = ['exchange', 'wallet'] as const; export type Source = typeof balanceTypes[number]; export type Asset = { - name: string; - address: string; + name: string + address: string } export type BalanceRequirement = { - readonly reason: string, - readonly asset: Asset, - readonly amount: string, - readonly sources: Source[], - readonly spenderAddress?: string; + readonly reason: string + readonly asset: Asset + readonly amount: string + readonly sources: Source[] + readonly spenderAddress?: string } export type AggregatedBalanceRequirement = { - readonly asset: Asset, - readonly sources: Source[], - readonly spenderAddress?: string; - items: Partial>, + readonly asset: Asset + readonly sources: Source[] + readonly spenderAddress?: string + items: Partial> } export type ApproveFix = { - readonly type: 'byApprove', - readonly targetAmount: BigNumber.Value, + readonly type: 'byApprove' + readonly targetAmount: BigNumber.Value readonly spenderAddress: string } export type DepositFix = { - readonly type: 'byDeposit', - readonly amount: BigNumber.Value, + readonly type: 'byDeposit' + readonly amount: BigNumber.Value readonly asset: string } type Fix = ApproveFix | DepositFix; export type BalanceIssue = { - readonly asset: Asset, - readonly message: string; - readonly sources: Source[], - readonly fixes?: Fix[], + readonly asset: Asset + readonly message: string + readonly sources: Source[] + readonly fixes?: Fix[] } export type Exchange = typeof exchanges[number]; export type OrderbookItem = { - price: string, - amount: string, - exchanges: Exchange[], - vob: { - side: 'BUY' | 'SELL', + price: string + amount: string + exchanges: Exchange[] + vob: Array<{ + side: 'BUY' | 'SELL' pairName: string - }[] + }> } export type SwapInfoAlternative = { - exchanges: Exchange[], - path: string[], - marketAmountOut?: number, - marketAmountIn?: number, - marketPrice: number, - availableAmountIn?: number, - availableAmountOut?: number, + exchanges: Exchange[] + path: string[] + marketAmountOut?: number + marketAmountIn?: number + marketPrice: number + availableAmountIn?: number + availableAmountOut?: number } export type SwapInfoBase = { - swapRequestId: string, - assetIn: string, - assetOut: string, - amountIn: number, - amountOut: number, - minAmountIn: number, - minAmountOut: number, + swapRequestId: string + assetIn: string + assetOut: string + amountIn: number + amountOut: number + minAmountIn: number + minAmountOut: number - path: string[], - exchanges?: Exchange[], - poolOptimal: boolean, + path: string[] + exchanges?: Exchange[] + poolOptimal: boolean - price?: number, - marketPrice?: number, + price?: number + marketPrice?: number orderInfo?: { - pair: string, - side: 'BUY' | 'SELL', - amount: number, - safePrice: number, - }, - alternatives: SwapInfoAlternative[], + pair: string + side: 'BUY' | 'SELL' + amount: number + safePrice: number + } + alternatives: SwapInfoAlternative[] } export type SwapInfoByAmountIn = SwapInfoBase & { - kind: 'exactSpend', - availableAmountIn?: number, - marketAmountOut?: number, + kind: 'exactSpend' + availableAmountIn?: number + marketAmountOut?: number } export type SwapInfoByAmountOut = SwapInfoBase & { - kind: 'exactReceive', - marketAmountIn?: number, - availableAmountOut?: number, + kind: 'exactReceive' + marketAmountIn?: number + availableAmountOut?: number } export type SwapInfo = SwapInfoByAmountIn | SwapInfoByAmountOut; export type FuturesTradeInfo = { - futuresTradeRequestId: string, - sender: string, - instrument: string, - buyPrice: number, - sellPrice: number, - buyPower: number, - sellPower: number, - minAmount: number, + futuresTradeRequestId: string + sender: string + instrument: string + buyPrice: number + sellPrice: number + buyPower: number + sellPower: number + minAmount: number } export enum HistoryTransactionStatus { @@ -255,30 +255,30 @@ export enum HistoryTransactionStatus { export type VerboseOrionUnitConfig = { // env?: string; // api: string; - chainId: SupportedChainId; - nodeJsonRpc: string; + chainId: SupportedChainId + nodeJsonRpc: string services: { orionBlockchain: { - http: string; + http: string // For example: // http://localhost:3001/, // http://10.123.34.23:3001/, // https://blockchain.orionprotocol.io/ - }, + } orionAggregator: { - http: string; - ws: string; + http: string + ws: string // For example: // http://localhost:3002/, // http://10.34.23.5:3002/, // shttps://aggregator.orionprotocol.io/ - }, + } priceFeed: { - api: string; + api: string // For example: // http://localhost:3003/, // http://10.23.5.11:3003/, // https://price-feed.orionprotocol.io/ - }, + } } -}; +} diff --git a/src/utils/checkIsToken.ts b/src/utils/checkIsToken.ts index 43aa6c3..dca4156 100644 --- a/src/utils/checkIsToken.ts +++ b/src/utils/checkIsToken.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import { ERC20__factory } from '@orionprotocol/contracts'; import { ethers } from 'ethers'; import invariant from 'tiny-invariant'; diff --git a/src/utils/denormalizeNumber.ts b/src/utils/denormalizeNumber.ts index 4221598..dbdda29 100644 --- a/src/utils/denormalizeNumber.ts +++ b/src/utils/denormalizeNumber.ts @@ -1,5 +1,5 @@ import BigNumber from 'bignumber.js'; -import { ethers } from 'ethers'; +import { type ethers } from 'ethers'; /** * Converts normalized blockchain ("machine-readable") number to denormalized ("human-readable") number. @@ -9,6 +9,6 @@ import { ethers } from 'ethers'; */ export default function denormalizeNumber(input: ethers.BigNumber, decimals: BigNumber.Value) { const decimalsBN = new BigNumber(decimals); - if (!decimalsBN.isInteger()) throw new Error(`Decimals '${decimals.toString()}' is not an integer`); + if (!decimalsBN.isInteger()) throw new Error(`Decimals '${decimalsBN.toString()}' is not an integer`); return new BigNumber(input.toString()).div(new BigNumber(10).pow(decimalsBN)); } diff --git a/src/utils/getAvailableFundsSources.ts b/src/utils/getAvailableFundsSources.ts index 9077d8f..982ec42 100644 --- a/src/utils/getAvailableFundsSources.ts +++ b/src/utils/getAvailableFundsSources.ts @@ -1,5 +1,5 @@ import { ethers } from 'ethers'; -import { Source } from '../types'; +import { type Source } from '../types'; export default function getAvailableFundsSources( expenseType: 'amount' | 'network_fee' | 'orion_fee', diff --git a/src/utils/getBalance.ts b/src/utils/getBalance.ts index eb8f0fd..b1a2469 100644 --- a/src/utils/getBalance.ts +++ b/src/utils/getBalance.ts @@ -1,10 +1,10 @@ -import { ERC20__factory, Exchange } from '@orionprotocol/contracts'; +import { ERC20__factory, type Exchange } from '@orionprotocol/contracts'; -import BigNumber from 'bignumber.js'; +import type BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; -import { utils } from '..'; import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION } from '../constants'; -import { OrionAggregator } from '../services/OrionAggregator'; +import { type OrionAggregator } from '../services/OrionAggregator'; +import denormalizeNumber from './denormalizeNumber'; export default async function getBalance( orionAggregator: OrionAggregator, @@ -25,13 +25,13 @@ export default async function getBalance( const assetDecimals = await assetContract.decimals(); assetWalletBalance = await assetContract.balanceOf(walletAddress); - denormalizedAssetInWalletBalance = utils.denormalizeNumber(assetWalletBalance, assetDecimals); + denormalizedAssetInWalletBalance = denormalizeNumber(assetWalletBalance, assetDecimals); } else { assetWalletBalance = await provider.getBalance(walletAddress); - denormalizedAssetInWalletBalance = utils.denormalizeNumber(assetWalletBalance, NATIVE_CURRENCY_PRECISION); + denormalizedAssetInWalletBalance = denormalizeNumber(assetWalletBalance, NATIVE_CURRENCY_PRECISION); } const assetContractBalance = await exchangeContract.getBalance(assetAddress, walletAddress); - const denormalizedAssetInContractBalance = utils.denormalizeNumber(assetContractBalance, INTERNAL_ORION_PRECISION); + const denormalizedAssetInContractBalance = denormalizeNumber(assetContractBalance, INTERNAL_ORION_PRECISION); const denormalizedAssetLockedBalanceResult = await orionAggregator.getLockedBalance(walletAddress, asset); if (denormalizedAssetLockedBalanceResult.isErr()) { throw new Error(denormalizedAssetLockedBalanceResult.error.message); diff --git a/src/utils/getBalances.ts b/src/utils/getBalances.ts index 98ddce8..0294070 100644 --- a/src/utils/getBalances.ts +++ b/src/utils/getBalances.ts @@ -1,7 +1,7 @@ -import { Exchange } from '@orionprotocol/contracts'; -import BigNumber from 'bignumber.js'; -import { ethers } from 'ethers'; -import { OrionAggregator } from '../services/OrionAggregator'; +import { type Exchange } from '@orionprotocol/contracts'; +import type BigNumber from 'bignumber.js'; +import { type ethers } from 'ethers'; +import { type OrionAggregator } from '../services/OrionAggregator'; import getBalance from './getBalance'; export default async ( @@ -14,7 +14,7 @@ export default async ( const balances = await Promise.all( Object.entries(balancesRequired) .map(async ([asset, assetAddress]) => { - if (!assetAddress) throw new Error(`Asset address of ${asset} not found`); + if (assetAddress === undefined) throw new Error(`Asset address of ${asset} not found`); const balance = await getBalance( orionAggregator, asset, @@ -31,8 +31,8 @@ export default async ( ); return balances.reduce>>((prev, curr) => ({ ...prev, [curr.asset]: curr.amount, diff --git a/src/utils/getNativeCryptocurrency.ts b/src/utils/getNativeCryptocurrency.ts index 73f2424..831ab7d 100644 --- a/src/utils/getNativeCryptocurrency.ts +++ b/src/utils/getNativeCryptocurrency.ts @@ -4,7 +4,7 @@ const getNativeCryptocurrency = (assetToAddress: Partial> const addressToAsset = Object .entries(assetToAddress) .reduce>>((prev, [asset, address]) => { - if (!address) return prev; + if (address === undefined) return prev; return { ...prev, [address]: asset, @@ -12,7 +12,7 @@ const getNativeCryptocurrency = (assetToAddress: Partial> }, {}); const nativeCryptocurrency = addressToAsset[ethers.constants.AddressZero]; - if (!nativeCryptocurrency) throw new Error('Native cryptocurrency asset is not found'); + if (nativeCryptocurrency === undefined) throw new Error('Native cryptocurrency asset is not found'); return nativeCryptocurrency; }; diff --git a/src/utils/httpError.ts b/src/utils/httpError.ts index aa2de14..708fbc9 100644 --- a/src/utils/httpError.ts +++ b/src/utils/httpError.ts @@ -1,14 +1,14 @@ export default class HttpError extends Error { public code: number; - public errorMessage: string |null; + public errorMessage: string | null; public statusText: string; public type: string; - constructor(code:number, message:string|null, type: string, statusText:string) { - super(message || ''); + constructor(code: number, message: string | null, type: string, statusText: string) { + super(message ?? ''); this.errorMessage = message; this.type = type; this.statusText = statusText; diff --git a/src/utils/index.ts b/src/utils/index.ts index a0a178b..93c2948 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -12,6 +12,7 @@ export { default as parseExchangeTradeTransaction } from './parseExchangeTradeTr export { default as toUpperCase } from './toUpperCase'; export { default as toLowerCase } from './toLowerCase'; export { default as isUppercasedNetworkCode } from './isUppercasedNetworkCode'; +export { default as getNativeCryptocurrency } from './getNativeCryptocurrency'; // export { default as HttpError } from './httpError'; diff --git a/src/utils/isNetworkCodeInEnvironment.ts b/src/utils/isNetworkCodeInEnvironment.ts index 042bc5a..56c4a82 100644 --- a/src/utils/isNetworkCodeInEnvironment.ts +++ b/src/utils/isNetworkCodeInEnvironment.ts @@ -6,7 +6,7 @@ export default function isNetworkCodeInEnvironment(networkCode: string, env: str } const envInfo = envs[env]; const envNetworks = envInfo?.networks; - if (envNetworks === undefined) throw new Error('Env networks is undefined (isNetworkCodeInEnvironment)'); + if (!envNetworks) throw new Error('Env networks is undefined (isNetworkCodeInEnvironment)'); return Object.values(chains) .some((chain) => chain.code.toLowerCase() === networkCode.toLowerCase() && diff --git a/src/utils/normalizeNumber.ts b/src/utils/normalizeNumber.ts index 4e83e32..c544d0f 100644 --- a/src/utils/normalizeNumber.ts +++ b/src/utils/normalizeNumber.ts @@ -14,7 +14,7 @@ export default function normalizeNumber( roundingMode: BigNumber.RoundingMode, ) { const decimalsBN = new BigNumber(decimals); - if (!decimalsBN.isInteger()) throw new Error(`Decimals '${decimals.toString()}' is not an integer`); + if (!decimalsBN.isInteger()) throw new Error(`Decimals '${decimalsBN.toString()}' is not an integer`); const inputBN = new BigNumber(input); return ethers.BigNumber.from( inputBN diff --git a/src/utils/objectKeys.ts b/src/utils/objectKeys.ts index b5a1514..6a5f17f 100644 --- a/src/utils/objectKeys.ts +++ b/src/utils/objectKeys.ts @@ -14,4 +14,4 @@ const untypedItems = Object.keys(items); // => Array @category Type guard */ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -export const objectKeys = Object.keys as (value: Type) => ObjectKeys[]; +export const objectKeys = Object.keys as (value: Type) => Array>; diff --git a/src/utils/typeHelpers.ts b/src/utils/typeHelpers.ts index a65cbb8..aff9c22 100644 --- a/src/utils/typeHelpers.ts +++ b/src/utils/typeHelpers.ts @@ -1,21 +1,21 @@ type WithReason = { - reason: string; + reason: string } type WithCodeError = Error & { - code: number | string; + code: number | string } type WithMessage = { - message: string; + message: string } type WithDataError = Error & { - data: Record; + data: Record } -type WithError ={ - error: Record; +type WithError = { + error: Record } export const makePartial = (value: Record): Partial> => value;