Linter standard (#49)

* Impl

* Fix

* Fix

* Bump

* Bump

* Fix

* Bump
This commit is contained in:
Aleksandr Kraiz
2023-02-14 00:34:37 +04:00
committed by GitHub
parent 7040df6142
commit c12a4e8e7a
48 changed files with 964 additions and 594 deletions

View File

@@ -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': [

View File

@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm test
# npm test

View File

@@ -11,5 +11,6 @@
"./README.md": [
"# Orion Protocol SDK"
]
}
},
"typescript.tsdk": "node_modules/typescript/lib"
}

296
package-lock.json generated
View File

@@ -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",

View File

@@ -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",

View File

@@ -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<BigNumber>((p, c) => (c ? p.plus(c) : p), new BigNumber(0));
.reduce<BigNumber>((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<BigNumber>((p, c) => (c ? p.plus(c) : p), new BigNumber(0));
.reduce<BigNumber>((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<BigNumber>((p, c) => (c ? p.plus(c) : p), new BigNumber(0));
.reduce<BigNumber>((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<BigNumber>((p, c) => (c ? p.plus(c) : p), new BigNumber(0));
.reduce<BigNumber>((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) {

View File

@@ -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<EnvConfig>
);
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<Partial<Record<SupportedChainId, OrionUnit>>>((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;

View File

@@ -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');

View File

@@ -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,

View File

@@ -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<SwapMarketParams, 'orionUnit'>
type PureSwapMarketParams = Omit<SwapMarketParams, 'orionUnit'>
type PureDepositParams = Omit<DepositParams, 'orionUnit'>
type PureWithdrawParams = Omit<WithdrawParams, 'orionUnit'>
type PureGetSwapMarketInfoParams= Omit<GetSwapInfoParams, 'orionBlockchain' | 'orionAggregator'>
type PureGetSwapMarketInfoParams = Omit<GetSwapInfoParams, 'orionBlockchain' | 'orionAggregator'>
export default class Exchange {
private readonly orionUnit: OrionUnit;

View File

@@ -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<Swap> {
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,

View File

@@ -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');

View File

@@ -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];

View File

@@ -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;

View File

@@ -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<boolean>((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', () => {

View File

@@ -1,4 +1,4 @@
import exchanges from './exchanges';
import type exchanges from './exchanges';
const mapping: Record<
typeof exchanges[number],

View File

@@ -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';

View File

@@ -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',
],
);

View File

@@ -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',
],
);

View File

@@ -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,

View File

@@ -1,5 +1,5 @@
import { ethers } from 'ethers';
import { CFDOrder } from '../types';
import { type CFDOrder } from '../types';
const { arrayify, joinSignature, splitSignature } = ethers.utils;

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -1,5 +1,5 @@
import { ethers } from 'ethers';
import { Order } from '../types';
import { type Order } from '../types';
const { arrayify, joinSignature, splitSignature } = ethers.utils;

View File

@@ -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<DataOut, DataIn, ErrorOut, Err
// payload
const fetchResult = await fromPromise(fetch(url, {
...options || {},
...options ?? {},
headers: {
'Cache-Control': 'no-store, max-age=0',
...(options ? options.headers : {}),

View File

@@ -1,4 +1,4 @@
import BigNumber from 'bignumber.js';
import type BigNumber from 'bignumber.js';
import { z } from 'zod';
import fetchWithValidation from '../../fetchWithValidation';
import swapInfoSchema from './schemas/swapInfoSchema';
@@ -9,12 +9,12 @@ import errorSchema from './schemas/errorSchema';
import placeAtomicSwapSchema from './schemas/placeAtomicSwapSchema';
import { OrionAggregatorWS } from './ws';
import { atomicSwapHistorySchema } from './schemas/atomicSwapHistorySchema';
import { Exchange, SignedCancelOrderRequest, SignedCFDOrder, SignedOrder } from '../../types';
import { type Exchange, type SignedCancelOrderRequest, type SignedCFDOrder, type SignedOrder } from '../../types';
import { pairConfigSchema } from './schemas';
import {
aggregatedOrderbookSchema, exchangeOrderbookSchema, poolReservesSchema,
} from './schemas/aggregatedOrderbookSchema';
import networkCodes from '../../constants/networkCodes';
import type networkCodes from '../../constants/networkCodes';
import toUpperCase from '../../utils/toUpperCase';
import httpToWS from '../../utils/httpToWS';
@@ -146,7 +146,7 @@ class OrionAggregator {
const headers = {
'Content-Type': 'application/json',
Accept: 'application/json',
...partnerId && { 'X-Partner-Id': partnerId },
...(partnerId !== undefined) && { 'X-Partner-Id': partnerId },
};
return fetchWithValidation(
@@ -232,7 +232,7 @@ class OrionAggregator {
} else {
url.searchParams.append('amountOut', amount);
}
if (exchanges) {
if (exchanges !== undefined) {
if (Array.isArray(exchanges)) {
exchanges.forEach((exchange) => {
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');
}

View File

@@ -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<Record<string, number>>) => void,
callback: (balances: Partial<Record<string, number>>) => void
}
type PairsConfigSubscription = {
callback: ({ kind, data }: {
kind: 'initial' | 'update',
data: Partial<Record<string, AssetPairUpdate>>,
}) => void,
kind: 'initial' | 'update'
data: Partial<Record<string, AssetPairUpdate>>
}) => 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<typeof orderUpdateSchema> | z.infer<typeof fullOrderSchema>
}
type AddressUpdateInitial = {
kind: 'initial',
kind: 'initial'
balances: Partial<
Record<
string,
Balance
>
>,
orders?: z.infer<typeof fullOrderSchema>[] // The field is not defined if the user has no orders
Record<
string,
Balance
>
>
orders?: Array<z.infer<typeof fullOrderSchema>> // The field is not defined if the user has no orders
}
type CfdAddressUpdateUpdate = {
kind: 'update',
balances?: CFDBalance[],
kind: 'update'
balances?: CFDBalance[]
order?: z.infer<typeof orderUpdateSchema> | z.infer<typeof fullOrderSchema>
}
type CfdAddressUpdateInitial = {
kind: 'initial',
balances: CFDBalance[],
orders?: z.infer<typeof fullOrderSchema>[] // The field is not defined if the user has no orders
kind: 'initial'
balances: CFDBalance[]
orders?: Array<z.infer<typeof fullOrderSchema>> // 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<unknown>
| ReadonlyArray<number>
| { valueOf(): ArrayBuffer }
| { valueOf(): SharedArrayBuffer }
| { valueOf(): Uint8Array }
| { valueOf(): ReadonlyArray<number> }
| { 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<z.infer<typeof fullOrderSchema>[]>((prev, o) => {
const fullOrders = (json.o)
? json.o.reduce<Array<z.infer<typeof fullOrderSchema>>>((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<Partial<Record<string, Balance>>>((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<z.infer<typeof fullOrderSchema>[]>((prev, o) => {
? json.o.reduce<Array<z.infer<typeof fullOrderSchema>>>((prev, o) => {
prev.push(o);
return prev;

View File

@@ -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;

View File

@@ -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<Record<string, string | number>>
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<Record<string, string | number>>
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);
};

View File

@@ -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;

View File

@@ -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]['schema']>
> = 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<T extends SubscriptionType = SubscriptionType> {
public readonly id: string;
@@ -104,16 +104,23 @@ export default class PriceFeedSubscription<T extends SubscriptionType = Subscrip
this.isClosedIntentionally = false;
const { payload, url, type } = this;
this.ws = new WebSocket(`${url}/${type}${payload ? `/${payload.toString()}` : ''}`);
this.ws = new WebSocket(`${url}/${type}${payload !== undefined ? `/${payload.toString()}` : ''}`);
this.ws.onmessage = (e) => {
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);
};

View File

@@ -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); },
};
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : 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<Record<string, string>>,
readonly asset: Asset
readonly sources: Source[]
readonly spenderAddress?: string
items: Partial<Record<string, string>>
}
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/
},
}
}
};
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable camelcase */
import { ERC20__factory } from '@orionprotocol/contracts';
import { ethers } from 'ethers';
import invariant from 'tiny-invariant';

View File

@@ -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));
}

View File

@@ -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',

View File

@@ -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);

View File

@@ -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<Partial<Record<string, {
exchange: BigNumber,
wallet: BigNumber,
exchange: BigNumber
wallet: BigNumber
}>>>((prev, curr) => ({
...prev,
[curr.asset]: curr.amount,

View File

@@ -4,7 +4,7 @@ const getNativeCryptocurrency = (assetToAddress: Partial<Record<string, string>>
const addressToAsset = Object
.entries(assetToAddress)
.reduce<Partial<Record<string, string>>>((prev, [asset, address]) => {
if (!address) return prev;
if (address === undefined) return prev;
return {
...prev,
[address]: asset,
@@ -12,7 +12,7 @@ const getNativeCryptocurrency = (assetToAddress: Partial<Record<string, string>>
}, {});
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;
};

View File

@@ -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;

View File

@@ -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';

View File

@@ -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() &&

View File

@@ -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

View File

@@ -14,4 +14,4 @@ const untypedItems = Object.keys(items); // => Array<string>
@category Type guard
*/
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
export const objectKeys = Object.keys as <Type extends object>(value: Type) => ObjectKeys<Type>[];
export const objectKeys = Object.keys as <Type extends object>(value: Type) => Array<ObjectKeys<Type>>;

View File

@@ -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<string, unknown>;
data: Record<string, unknown>
}
type WithError ={
error: Record<string | number | symbol, unknown>;
type WithError = {
error: Record<string | number | symbol, unknown>
}
export const makePartial = <Key extends string | number | symbol, Value>(value: Record<Key, Value>): Partial<Record<Key, Value>> => value;