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, node: true,
}, },
extends: [ extends: [
'standard', 'standard-with-typescript',
'eslint:recommended', 'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking', 'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:@typescript-eslint/strict',
'plugin:import/recommended',
'plugin:import/typescript' 'plugin:import/typescript'
], ],
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
@@ -26,6 +28,39 @@ module.exports = {
'@typescript-eslint', '@typescript-eslint',
], ],
rules: { 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, "comma-dangle": 0,
"semi": 0, "semi": 0,
"space-before-function-paren": 0, "space-before-function-paren": 0,
@@ -61,6 +96,8 @@ module.exports = {
2, 2,
{ {
ignoreComments: true, ignoreComments: true,
ignoreUrls: true,
ignoreTemplateLiterals: true,
} }
], ],
'import/extensions': [ 'import/extensions': [

View File

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

View File

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

296
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "@orionprotocol/sdk", "name": "@orionprotocol/sdk",
"version": "0.17.5-rc.0", "version": "0.17.7-rc.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@orionprotocol/sdk", "name": "@orionprotocol/sdk",
"version": "0.17.5-rc.0", "version": "0.17.7-rc.1",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0",
@@ -52,6 +52,7 @@
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.6.1", "eslint-plugin-n": "^15.6.1",
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-promise": "^6.1.1",
"http-terminator": "^3.2.0",
"husky": "^7.0.4", "husky": "^7.0.4",
"is-ci": "^3.0.1", "is-ci": "^3.0.1",
"jest": "^29.4.2", "jest": "^29.4.2",
@@ -3835,6 +3836,12 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" "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": { "node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -4549,6 +4556,18 @@
"url": "https://github.com/sponsors/ljharb" "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": { "node_modules/delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -5648,12 +5667,39 @@
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true "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": { "node_modules/fast-levenshtein": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true "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": { "node_modules/fastest-levenshtein": {
"version": "1.0.16", "version": "1.0.16",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
@@ -5984,6 +6030,21 @@
"node": ">=4" "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": { "node_modules/globby": {
"version": "11.1.0", "version": "11.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
@@ -6179,6 +6240,33 @@
"node": ">= 0.8" "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": { "node_modules/human-signals": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -9093,6 +9181,15 @@
"node": ">=0.10.0" "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": { "node_modules/p-limit": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -9123,6 +9220,18 @@
"url": "https://github.com/sponsors/sindresorhus" "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": { "node_modules/p-try": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -9132,6 +9241,21 @@
"node": ">=6" "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": { "node_modules/parent-module": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -9657,6 +9781,12 @@
"node": ">=0.10.0" "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": { "node_modules/rimraf": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -9681,6 +9811,23 @@
"inherits": "^2.0.1" "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": { "node_modules/run-parallel": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -9746,6 +9893,15 @@
"url": "https://github.com/sponsors/ljharb" "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": { "node_modules/safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -9783,6 +9939,12 @@
"semver": "bin/semver.js" "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": { "node_modules/send": {
"version": "0.18.0", "version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
@@ -10029,6 +10191,12 @@
"node": ">=10" "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": { "node_modules/string-width": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "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": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -14496,6 +14670,12 @@
"object-keys": "^1.1.1" "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": { "delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -15325,12 +15505,33 @@
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true "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": { "fast-levenshtein": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true "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": { "fastest-levenshtein": {
"version": "1.0.16", "version": "1.0.16",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "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==", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true "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": { "globby": {
"version": "11.1.0", "version": "11.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
@@ -15726,6 +15936,26 @@
"toidentifier": "1.0.1" "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": { "human-signals": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -17854,6 +18084,12 @@
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"dev": true "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": { "p-limit": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -17872,12 +18108,30 @@
"p-limit": "^3.0.2" "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": { "p-try": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true "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": { "parent-module": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -18261,6 +18515,12 @@
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true "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": { "rimraf": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -18279,6 +18539,20 @@
"inherits": "^2.0.1" "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": { "run-parallel": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -18313,6 +18587,12 @@
"is-regex": "^1.1.4" "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": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -18340,6 +18620,12 @@
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true "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": { "send": {
"version": "0.18.0", "version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
@@ -18550,6 +18836,12 @@
"strip-ansi": "^6.0.0" "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": { "string-width": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@orionprotocol/sdk", "name": "@orionprotocol/sdk",
"version": "0.17.6", "version": "0.17.7-rc.3",
"description": "Orion Protocol SDK", "description": "Orion Protocol SDK",
"main": "./lib/esm/index.js", "main": "./lib/esm/index.js",
"module": "./lib/esm/index.js", "module": "./lib/esm/index.js",
@@ -59,6 +59,7 @@
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.6.1", "eslint-plugin-n": "^15.6.1",
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-promise": "^6.1.1",
"http-terminator": "^3.2.0",
"husky": "^7.0.4", "husky": "^7.0.4",
"is-ci": "^3.0.1", "is-ci": "^3.0.1",
"jest": "^29.4.2", "jest": "^29.4.2",

View File

@@ -2,7 +2,6 @@ import BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import clone from 'just-clone'; import clone from 'just-clone';
import { ERC20__factory } from '@orionprotocol/contracts'; import { ERC20__factory } from '@orionprotocol/contracts';
import { utils } from '.';
import { APPROVE_ERC20_GAS_LIMIT, NATIVE_CURRENCY_PRECISION } from './constants'; import { APPROVE_ERC20_GAS_LIMIT, NATIVE_CURRENCY_PRECISION } from './constants';
import type { import type {
AggregatedBalanceRequirement, ApproveFix, Asset, BalanceIssue, BalanceRequirement, Source, AggregatedBalanceRequirement, ApproveFix, Asset, BalanceIssue, BalanceRequirement, Source,
@@ -16,7 +15,8 @@ export default class BalanceGuard {
string, string,
Record< Record<
'exchange' | 'wallet', 'exchange' | 'wallet',
BigNumber> BigNumber
>
> >
>; >;
@@ -109,7 +109,7 @@ export default class BalanceGuard {
}, []); }, []);
} }
private fixAllAutofixableBalanceIssues = async ( private readonly fixAllAutofixableBalanceIssues = async (
balanceIssues: BalanceIssue[], balanceIssues: BalanceIssue[],
) => { ) => {
const fixBalanceIssue = async (issue: BalanceIssue) => { const fixBalanceIssue = async (issue: BalanceIssue) => {
@@ -146,8 +146,8 @@ export default class BalanceGuard {
}; };
await issue.fixes?.reduce(async (promise, item) => { await issue.fixes?.reduce(async (promise, item) => {
await promise; await promise;
if (item.type === 'byApprove') return approve(item); if (item.type === 'byApprove') { await approve(item); return; }
return promise; await promise;
}, Promise.resolve()); }, Promise.resolve());
}; };
@@ -155,7 +155,7 @@ export default class BalanceGuard {
await autofixableBalanceIssues.reduce(async (promise, item) => { await autofixableBalanceIssues.reduce(async (promise, item) => {
await promise; await promise;
return fixBalanceIssue(item); await fixBalanceIssue(item);
}, Promise.resolve()); }, Promise.resolve());
return balanceIssues.filter((item) => !autofixableBalanceIssues.includes(item)); return balanceIssues.filter((item) => !autofixableBalanceIssues.includes(item));
@@ -196,18 +196,18 @@ export default class BalanceGuard {
const remainingBalance = remainingBalances[asset.name]; const remainingBalance = remainingBalances[asset.name];
if (!remainingBalance) throw new Error(`No ${asset.name} balance`); if (!remainingBalance) throw new Error(`No ${asset.name} balance`);
const itemsAmountSum = Object.values(items) 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); remainingBalance.exchange = remainingBalance.exchange.minus(itemsAmountSum);
if (remainingBalance.exchange.lt(0)) { if (remainingBalance.exchange.lt(0)) {
const lackAmount = remainingBalance.exchange.abs(); const lackAmount = remainingBalance.exchange.abs();
const exchangeBalance = this.balances?.[asset.name]?.exchange; const exchangeBalance = this.balances[asset.name]?.exchange;
balanceIssues.push({ balanceIssues.push({
asset, asset,
sources: ['exchange'], sources: ['exchange'],
message: `Not enough ${asset.name} on exchange balance. ` + 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`, `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]; const remainingBalance = remainingBalances[asset.name];
if (!remainingBalance) throw new Error(`No ${asset.name} balance`); if (!remainingBalance) throw new Error(`No ${asset.name} balance`);
const itemsAmountSum = Object.values(items) 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); remainingBalance.exchange = remainingBalance.exchange.minus(itemsAmountSum);
if (remainingBalance.exchange.lt(0)) { if (remainingBalance.exchange.lt(0)) {
@@ -233,7 +233,7 @@ export default class BalanceGuard {
if (asset.address === ethers.constants.AddressZero) { if (asset.address === ethers.constants.AddressZero) {
denormalizedAllowance = remainingBalance.wallet; denormalizedAllowance = remainingBalance.wallet;
} else { } 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 tokenContract = ERC20__factory.connect(asset.address, this.provider);
const tokenDecimals = await tokenContract.decimals(); const tokenDecimals = await tokenContract.decimals();
const tokenAllowance = await tokenContract.allowance(walletAddress, spenderAddress); const tokenAllowance = await tokenContract.allowance(walletAddress, spenderAddress);
@@ -257,17 +257,17 @@ export default class BalanceGuard {
const approveIsHelpful = approveAvailable.gte(lackAmount); const approveIsHelpful = approveAvailable.gte(lackAmount);
const targetApprove = approvedWalletBalance.plus(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 available = exchangeBalance?.plus(approvedWalletBalance);
const issueMessage = `Not enough ${asset.name} on exchange + wallet balance. ` + const issueMessage = `Not enough ${asset.name} on exchange + wallet balance. ` +
`Needed: ${itemsAmountSum.toString()}, available: ${(available ?? '[UNDEFINED]')?.toString()} ` + `Needed: ${itemsAmountSum.toString()}, available: ${(available ?? '[UNDEFINED]').toString()} ` +
`(exchange: ${(exchangeBalance ?? '[UNKNOWN]')?.toString()}, available (approved): ${approvedWalletBalance.toString()}).` + `(exchange: ${(exchangeBalance ?? '[UNKNOWN]').toString()}, available (approved): ${approvedWalletBalance.toString()}).` +
` ${approveIsHelpful ` ${approveIsHelpful
? `You need approve at least ${lackAmount.toString()} ${asset.name}` ? `You need approve at least ${lackAmount.toString()} ${asset.name}`
: 'Approve is not helpful'}`; : 'Approve is not helpful'}`;
if (approveIsHelpful) { 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( const resetRequired = await this.checkResetRequired(
asset.address, asset.address,
spenderAddress, spenderAddress,
@@ -276,8 +276,10 @@ export default class BalanceGuard {
const approveTransactionCost = ethers.BigNumber const approveTransactionCost = ethers.BigNumber
.from(APPROVE_ERC20_GAS_LIMIT) .from(APPROVE_ERC20_GAS_LIMIT)
.mul(gasPriceWei); .mul(gasPriceWei);
const denormalizedApproveTransactionCost = utils const denormalizedApproveTransactionCost = denormalizeNumber(
.denormalizeNumber(approveTransactionCost, NATIVE_CURRENCY_PRECISION); approveTransactionCost,
NATIVE_CURRENCY_PRECISION
);
requiredApproves.items = { requiredApproves.items = {
...requiredApproves.items, ...requiredApproves.items,
@@ -324,13 +326,13 @@ export default class BalanceGuard {
const remainingBalance = remainingBalances[asset.name]; const remainingBalance = remainingBalances[asset.name];
if (!remainingBalance) throw new Error(`No ${asset.name} balance`); if (!remainingBalance) throw new Error(`No ${asset.name} balance`);
const itemsAmountSum = Object.values(items) 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; let denormalizedAllowance: BigNumber;
if (asset.address === ethers.constants.AddressZero) { if (asset.address === ethers.constants.AddressZero) {
denormalizedAllowance = remainingBalance.wallet; denormalizedAllowance = remainingBalance.wallet;
} else { } 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 tokenContract = ERC20__factory.connect(asset.address, this.provider);
const tokenDecimals = await tokenContract.decimals(); const tokenDecimals = await tokenContract.decimals();
const tokenAllowance = await tokenContract.allowance(walletAddress, spenderAddress); const tokenAllowance = await tokenContract.allowance(walletAddress, spenderAddress);
@@ -358,7 +360,7 @@ export default class BalanceGuard {
? `You need approve at least ${lackAmount.toString()} ${asset.name}` ? `You need approve at least ${lackAmount.toString()} ${asset.name}`
: 'Approve is not helpful'}`; : 'Approve is not helpful'}`;
if (approveIsHelpful) { 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( const resetRequired = await this.checkResetRequired(
asset.address, asset.address,
spenderAddress, spenderAddress,
@@ -367,8 +369,10 @@ export default class BalanceGuard {
const approveTransactionCost = ethers.BigNumber const approveTransactionCost = ethers.BigNumber
.from(APPROVE_ERC20_GAS_LIMIT) .from(APPROVE_ERC20_GAS_LIMIT)
.mul(gasPriceWei); .mul(gasPriceWei);
const denormalizedApproveTransactionCost = utils const denormalizedApproveTransactionCost = denormalizeNumber(
.denormalizeNumber(approveTransactionCost, NATIVE_CURRENCY_PRECISION); approveTransactionCost,
NATIVE_CURRENCY_PRECISION
);
requiredApproves.items = { requiredApproves.items = {
...requiredApproves.items, ...requiredApproves.items,
@@ -414,7 +418,7 @@ export default class BalanceGuard {
if (!remainingBalance) throw new Error(`No ${asset.name} balance`); if (!remainingBalance) throw new Error(`No ${asset.name} balance`);
const itemsAmountSum = Object.values({ ...items, ...requiredApproves.items }) 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); remainingBalance.wallet = remainingBalance.wallet.minus(itemsAmountSum);
if (remainingBalance.wallet.lt(0)) { 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); 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')}`); if (unfixed.length > 0) throw new Error(`Balance issues: ${unfixed.map((issue, i) => `${i + 1}. ${issue.message}`).join('\n')}`);
} else if (balanceIssues.length > 0) { } else if (balanceIssues.length > 0) {

View File

@@ -1,21 +1,21 @@
import { merge } from 'merge-anything'; import { merge } from 'merge-anything';
import { chains, envs } from '../config'; import { chains, envs } from '../config';
import { networkCodes } from '../constants'; import { type networkCodes } from '../constants';
import OrionUnit from '../OrionUnit'; import OrionUnit from '../OrionUnit';
import OrionAnalytics from '../services/OrionAnalytics'; import OrionAnalytics from '../services/OrionAnalytics';
import { ReferralSystem } from '../services/ReferralSystem'; import { ReferralSystem } from '../services/ReferralSystem';
import { DeepPartial, SupportedChainId, VerboseOrionUnitConfig } from '../types'; import { type DeepPartial, type SupportedChainId, type VerboseOrionUnitConfig } from '../types';
import { isValidChainId } from '../utils'; import { isValidChainId } from '../utils';
type EnvConfig = { type EnvConfig = {
analyticsAPI: string; analyticsAPI: string
referralAPI: string; referralAPI: string
networks: Partial< networks: Partial<
Record< Record<
SupportedChainId, SupportedChainId,
VerboseOrionUnitConfig VerboseOrionUnitConfig
> >
>; >
} }
type KnownEnv = 'testing' | 'staging' | 'production'; type KnownEnv = 'testing' | 'staging' | 'production';
@@ -29,14 +29,6 @@ export default class Orion {
public readonly referralSystem: ReferralSystem; public readonly referralSystem: ReferralSystem;
constructor();
constructor(
env: KnownEnv,
overrides?: DeepPartial<EnvConfig>
);
constructor(config: EnvConfig);
// TODO: get tradable assets (aggregated) // TODO: get tradable assets (aggregated)
// TODO: get tradable pairs (aggregated) // TODO: get tradable pairs (aggregated)
@@ -50,7 +42,9 @@ export default class Orion {
let config: EnvConfig; let config: EnvConfig;
if (typeof envOrConfig === 'string') { if (typeof envOrConfig === 'string') {
const envConfig = envs[envOrConfig]; 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; this.env = envOrConfig;
config = { config = {
analyticsAPI: envConfig.analyticsAPI, analyticsAPI: envConfig.analyticsAPI,
@@ -58,13 +52,15 @@ export default class Orion {
networks: Object.entries(envConfig.networks).map(([chainId, networkConfig]) => { networks: Object.entries(envConfig.networks).map(([chainId, networkConfig]) => {
if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`); if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`);
const chainConfig = chains[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 { return {
env: envOrConfig, env: envOrConfig,
chainId, chainId,
api: networkConfig.api, api: networkConfig.api,
nodeJsonRpc: networkConfig?.rpc ?? chainConfig.rpc, nodeJsonRpc: networkConfig.rpc ?? chainConfig.rpc,
services: { services: {
orionBlockchain: { orionBlockchain: {
http: networkConfig.api + networkConfig.services.blockchain.http, http: networkConfig.api + networkConfig.services.blockchain.http,
@@ -86,6 +82,7 @@ export default class Orion {
}; };
if (overrides) { if (overrides) {
// Recursive merge of config and overrides. Ignore undefined values.
config = merge(config, overrides); config = merge(config, overrides);
} }
} else { } else {
@@ -99,7 +96,7 @@ export default class Orion {
.reduce<Partial<Record<SupportedChainId, OrionUnit>>>((acc, [chainId, networkConfig]) => { .reduce<Partial<Record<SupportedChainId, OrionUnit>>>((acc, [chainId, networkConfig]) => {
if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`); if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`);
const chainConfig = chains[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({ const orionUnit = new OrionUnit({
// env: networkConfig.env, // env: networkConfig.env,
@@ -119,11 +116,7 @@ export default class Orion {
return Object.entries(this.units).map(([, unit]) => unit); return Object.entries(this.units).map(([, unit]) => unit);
} }
getUnit(chainId: SupportedChainId): OrionUnit; getUnit(networkCodeOrChainId: typeof networkCodes[number] | SupportedChainId): OrionUnit {
getUnit(networkCode: typeof networkCodes[number]): OrionUnit;
getUnit(networkCodeOrChainId: string): OrionUnit {
let unit: OrionUnit | undefined; let unit: OrionUnit | undefined;
if (isValidChainId(networkCodeOrChainId)) { if (isValidChainId(networkCodeOrChainId)) {
unit = this.units[networkCodeOrChainId]; unit = this.units[networkCodeOrChainId];

View File

@@ -1,23 +1,21 @@
/* eslint-disable max-len */
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Exchange__factory } from '@orionprotocol/contracts'; import { Exchange__factory } from '@orionprotocol/contracts';
import getBalances from '../../utils/getBalances'; import getBalances from '../../utils/getBalances';
import BalanceGuard from '../../BalanceGuard'; import BalanceGuard from '../../BalanceGuard';
import OrionUnit from '..'; import type OrionUnit from '..';
import { utils } from '../..';
import { import {
DEPOSIT_ERC20_GAS_LIMIT, DEPOSIT_ETH_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, DEPOSIT_ERC20_GAS_LIMIT, DEPOSIT_ETH_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION,
} from '../../constants'; } from '../../constants';
import { normalizeNumber } from '../../utils'; import { denormalizeNumber, normalizeNumber } from '../../utils';
import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency';
import simpleFetch from '../../simpleFetch'; import simpleFetch from '../../simpleFetch';
export type DepositParams = { export type DepositParams = {
asset: string, asset: string
amount: BigNumber.Value, amount: BigNumber.Value
signer: ethers.Signer, signer: ethers.Signer
orionUnit: OrionUnit, orionUnit: OrionUnit
} }
export default async function deposit({ export default async function deposit({
@@ -29,8 +27,8 @@ export default async function deposit({
if (asset === '') throw new Error('Asset can not be empty'); if (asset === '') throw new Error('Asset can not be empty');
const amountBN = new BigNumber(amount); const amountBN = new BigNumber(amount);
if (amountBN.isNaN()) throw new Error(`Amount '${amount.toString()}' is not a number`); if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`);
if (amountBN.lte(0)) throw new Error(`Amount '${amount.toString()}' should be greater than 0`); if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`);
const walletAddress = await signer.getAddress(); const walletAddress = await signer.getAddress();
@@ -48,7 +46,7 @@ export default async function deposit({
const gasPriceWei = await simpleFetch(orionBlockchain.getGasPriceWei)(); const gasPriceWei = await simpleFetch(orionBlockchain.getGasPriceWei)();
const assetAddress = assetToAddress[asset]; 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( const balances = await getBalances(
{ {
@@ -77,7 +75,7 @@ export default async function deposit({
name: asset, name: asset,
address: assetAddress, address: assetAddress,
}, },
amount: amount.toString(), amount: amountBN.toString(),
spenderAddress: exchangeContractAddress, spenderAddress: exchangeContractAddress,
sources: ['wallet'], sources: ['wallet'],
}); });
@@ -96,7 +94,7 @@ export default async function deposit({
} }
const transactionCost = ethers.BigNumber.from(unsignedTx.gasLimit).mul(gasPriceWei); 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({ balanceGuard.registerRequirement({
reason: 'Network fee', reason: 'Network fee',
@@ -121,7 +119,7 @@ export default async function deposit({
const txResponse = await provider.sendTransaction(signedTx); const txResponse = await provider.sendTransaction(signedTx);
console.log(`Deposit tx sent: ${txResponse.hash}. Waiting for confirmation...`); console.log(`Deposit tx sent: ${txResponse.hash}. Waiting for confirmation...`);
const txReceipt = await txResponse.wait(); const txReceipt = await txResponse.wait();
if (txReceipt.status) { if (txReceipt.status !== undefined) {
console.log('Deposit tx confirmed'); console.log('Deposit tx confirmed');
} else { } else {
console.log('Deposit tx failed'); console.log('Deposit tx failed');

View File

@@ -1,24 +1,23 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { utils } from '../..';
import { NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants'; import { NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants';
import { OrionAggregator } from '../../services/OrionAggregator'; import { type OrionAggregator } from '../../services/OrionAggregator';
import { OrionBlockchain } from '../../services/OrionBlockchain'; import { type OrionBlockchain } from '../../services/OrionBlockchain';
import simpleFetch from '../../simpleFetch'; import simpleFetch from '../../simpleFetch';
import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; import { calculateFeeInFeeAsset, denormalizeNumber, getNativeCryptocurrency } from '../../utils';
export type GetSwapInfoParams = { export type GetSwapInfoParams = {
type: 'exactSpend' | 'exactReceive', type: 'exactSpend' | 'exactReceive'
assetIn: string, assetIn: string
assetOut: string, assetOut: string
amount: BigNumber.Value, amount: BigNumber.Value
feeAsset: string, feeAsset: string
orionBlockchain: OrionBlockchain, orionBlockchain: OrionBlockchain
orionAggregator: OrionAggregator orionAggregator: OrionAggregator
options?: { options?: {
instantSettlement?: boolean, instantSettlement?: boolean
poolOnly?: boolean, poolOnly?: boolean
} }
} }
@@ -38,8 +37,8 @@ export default async function getSwapInfo({
if (feeAsset === '') throw new Error('Fee asset can not be empty'); if (feeAsset === '') throw new Error('Fee asset can not be empty');
const amountBN = new BigNumber(amount); const amountBN = new BigNumber(amount);
if (amountBN.isNaN()) throw new Error(`Amount '${amount.toString()}' is not a number`); if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`);
if (amountBN.lte(0)) throw new Error(`Amount '${amount.toString()}' should be greater than 0`); if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`);
const { const {
assetToAddress, assetToAddress,
@@ -53,17 +52,21 @@ export default async function getSwapInfo({
const gasPriceGwei = ethers.utils.formatUnits(gasPriceWei, 'gwei').toString(); const gasPriceGwei = ethers.utils.formatUnits(gasPriceWei, 'gwei').toString();
const assetInAddress = assetToAddress[assetIn]; 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]; 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)( const swapInfo = await simpleFetch(orionAggregator.getSwapInfo)(
type, type,
assetIn, assetIn,
assetOut, assetOut,
amount.toString(), amountBN.toString(),
options?.instantSettlement, options?.instantSettlement,
options?.poolOnly ? 'pools' : undefined, options?.poolOnly !== undefined && options.poolOnly
? 'pools'
: undefined,
); );
const { exchanges: swapExchanges } = swapInfo; const { exchanges: swapExchanges } = swapInfo;
@@ -82,13 +85,12 @@ export default async function getSwapInfo({
// if (swapInfo.orderInfo === null) throw new Error(swapInfo.executionInfo); // if (swapInfo.orderInfo === null) throw new Error(swapInfo.executionInfo);
let route: 'pool' | 'aggregator'; let route: 'pool' | 'aggregator';
if (options?.poolOnly) { if (options?.poolOnly !== undefined && options.poolOnly) {
route = 'pool'; route = 'pool';
} else if ( } else if (
swapExchanges !== undefined &&
poolExchangesList.length > 0 && poolExchangesList.length > 0 &&
swapExchanges.length === 1 && swapExchanges.length === 1 &&
firstSwapExchange && firstSwapExchange !== undefined &&
poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange) poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange)
) { ) {
route = 'pool'; route = 'pool';
@@ -98,7 +100,7 @@ export default async function getSwapInfo({
if (route === 'pool') { if (route === 'pool') {
const transactionCost = ethers.BigNumber.from(SWAP_THROUGH_ORION_POOL_GAS_LIMIT).mul(gasPriceWei); 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 { return {
route, route,
@@ -112,26 +114,26 @@ export default async function getSwapInfo({
}; };
} }
if (swapInfo.orderInfo) { if (swapInfo.orderInfo !== null) {
const [baseAssetName] = swapInfo.orderInfo.assetPair.split('-'); const [baseAssetName] = swapInfo.orderInfo.assetPair.split('-');
if (baseAssetName === undefined) throw new Error('Base asset name is undefined'); if (baseAssetName === undefined) throw new Error('Base asset name is undefined');
const baseAssetAddress = assetToAddress[baseAssetName]; 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 // Fee calculation
const baseAssetPriceInOrn = pricesInOrn?.[baseAssetAddress]; const baseAssetPriceInOrn = pricesInOrn[baseAssetAddress];
if (!baseAssetPriceInOrn) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); if (baseAssetPriceInOrn === undefined) throw new Error(`Base asset price ${baseAssetName} in ORN not found`);
const baseCurrencyPriceInOrn = pricesInOrn[ethers.constants.AddressZero]; 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]; const feeAssetPriceInOrn = pricesInOrn[feeAssetAddress];
if (!feeAssetPriceInOrn) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); if (feeAssetPriceInOrn === undefined) throw new Error(`Fee asset price ${feeAsset} in ORN not found`);
const feePercent = feeAssets?.[feeAsset]; const feePercent = feeAssets[feeAsset];
if (!feePercent) throw new Error(`Fee asset ${feeAsset} not available`); if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`);
const { const {
orionFeeInFeeAsset, orionFeeInFeeAsset,
networkFeeInFeeAsset, networkFeeInFeeAsset,
} = utils.calculateFeeInFeeAsset( } = calculateFeeInFeeAsset(
swapInfo.orderInfo.amount, swapInfo.orderInfo.amount,
feeAssetPriceInOrn, feeAssetPriceInOrn,
baseAssetPriceInOrn, baseAssetPriceInOrn,

View File

@@ -1,8 +1,8 @@
import OrionUnit from '..'; import type OrionUnit from '..';
import deposit, { DepositParams } from './deposit'; import deposit, { type DepositParams } from './deposit';
import getSwapInfo, { GetSwapInfoParams } from './getSwapInfo'; import getSwapInfo, { type GetSwapInfoParams } from './getSwapInfo';
import swapMarket, { SwapMarketParams } from './swapMarket'; import swapMarket, { type SwapMarketParams } from './swapMarket';
import withdraw, { WithdrawParams } from './withdraw'; import withdraw, { type WithdrawParams } from './withdraw';
type PureSwapMarketParams = Omit<SwapMarketParams, 'orionUnit'> type PureSwapMarketParams = Omit<SwapMarketParams, 'orionUnit'>
type PureDepositParams = Omit<DepositParams, 'orionUnit'> type PureDepositParams = Omit<DepositParams, 'orionUnit'>

View File

@@ -1,47 +1,47 @@
/* eslint-disable max-len */
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Exchange__factory } from '@orionprotocol/contracts'; import { Exchange__factory } from '@orionprotocol/contracts';
import getBalances from '../../utils/getBalances'; import getBalances from '../../utils/getBalances';
import BalanceGuard from '../../BalanceGuard'; import BalanceGuard from '../../BalanceGuard';
import getAvailableSources from '../../utils/getAvailableFundsSources'; import getAvailableSources from '../../utils/getAvailableFundsSources';
import OrionUnit from '..'; import type OrionUnit from '..';
import { crypt, utils } from '../..';
import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants'; import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants';
import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency';
import simpleFetch from '../../simpleFetch'; import simpleFetch from '../../simpleFetch';
import { calculateFeeInFeeAsset, denormalizeNumber, normalizeNumber } from '../../utils';
import { signOrder } from '../../crypt';
export type SwapMarketParams = { export type SwapMarketParams = {
type: 'exactSpend' | 'exactReceive', type: 'exactSpend' | 'exactReceive'
assetIn: string, assetIn: string
assetOut: string, assetOut: string
amount: BigNumber.Value, amount: BigNumber.Value
feeAsset: string, feeAsset: string
slippagePercent: BigNumber.Value, slippagePercent: BigNumber.Value
signer: ethers.Signer, signer: ethers.Signer
orionUnit: OrionUnit, orionUnit: OrionUnit
options?: { options?: {
poolOnly?: boolean, poolOnly?: boolean
instantSettlement?: boolean, instantSettlement?: boolean
logger?: (message: string) => void, logger?: (message: string) => void
autoApprove?: boolean, autoApprove?: boolean
developer?: { developer?: {
route?: 'aggregator' | 'pool', route?: 'aggregator' | 'pool'
} }
} }
} }
type AggregatorOrder = { type AggregatorOrder = {
through: 'aggregator' through: 'aggregator'
id: string, id: string
} }
type PoolSwap = { type PoolSwap = {
through: 'orion_pool' through: 'orion_pool'
txHash: string, txHash: string
} }
type Swap = AggregatorOrder | PoolSwap; export type Swap = AggregatorOrder | PoolSwap;
export default async function swapMarket({ export default async function swapMarket({
type, type,
@@ -54,7 +54,7 @@ export default async function swapMarket({
orionUnit, orionUnit,
options, options,
}: SwapMarketParams): Promise<Swap> { }: 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 (amount === '') throw new Error('Amount can not be empty');
if (assetIn === '') throw new Error('AssetIn can not be empty'); if (assetIn === '') throw new Error('AssetIn can not be empty');
if (assetOut === '') throw new Error('AssetOut 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'); if (slippagePercent === '') throw new Error('Slippage percent can not be empty');
const amountBN = new BigNumber(amount); const amountBN = new BigNumber(amount);
if (amountBN.isNaN()) throw new Error(`Amount '${amount.toString()}' is not a number`); if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`);
if (amountBN.lte(0)) throw new Error(`Amount '${amount.toString()}' should be greater than 0`); if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`);
const slippagePercentBN = new BigNumber(slippagePercent); 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.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'); 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 gasPriceGwei = ethers.utils.formatUnits(gasPriceWei, 'gwei').toString();
const assetInAddress = assetToAddress[assetIn]; 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]; 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( const balances = await getBalances(
{ {
@@ -124,16 +126,18 @@ export default async function swapMarket({
type, type,
assetIn, assetIn,
assetOut, assetOut,
amount.toString(), amountBN.toString(),
options?.instantSettlement, options?.instantSettlement,
options?.poolOnly ? 'pools' : undefined, options?.poolOnly !== undefined && options.poolOnly
? 'pools'
: undefined,
); );
const { exchanges: swapExchanges } = swapInfo; const { exchanges: swapExchanges } = swapInfo;
const [firstSwapExchange] = swapExchanges; 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)) { if (swapInfo.type === 'exactReceive' && amountBN.lt(swapInfo.minAmountOut)) {
throw new Error(`Amount is too low. Min amountOut is ${swapInfo.minAmountOut} ${assetOut}`); 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'); if (quoteAssetName === undefined) throw new Error('Quote asset name is undefined');
const pairConfig = await simpleFetch(orionAggregator.getPairConfig)(`${baseAssetName}-${quoteAssetName}`); 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 qtyPrecisionBN = new BigNumber(pairConfig.qtyPrecision);
const qtyDecimalPlaces = amountBN.dp(); const qtyDecimalPlaces = amountBN.dp();
if (qtyDecimalPlaces === null) throw new Error('Qty decimal places is null. Likely amount is -Infinity, +Infinity or NaN'); 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'; let route: 'aggregator' | 'pool';
@@ -165,15 +171,14 @@ export default async function swapMarket({
if (options?.developer?.route !== undefined) { if (options?.developer?.route !== undefined) {
route = options.developer.route; route = options.developer.route;
options?.logger?.(`Swap is through ${route} (because route forced to ${route})`); options.logger?.(`Swap is through ${route} (because route forced to ${route})`);
} else if (options?.poolOnly) { } else if (options?.poolOnly !== undefined && options.poolOnly) {
options?.logger?.('Swap is through pool (because "poolOnly" option is true)'); options.logger?.('Swap is through pool (because "poolOnly" option is true)');
route = 'pool'; route = 'pool';
} else if ( } else if (
swapExchanges !== undefined &&
poolExchangesList.length > 0 && poolExchangesList.length > 0 &&
swapExchanges.length === 1 && swapExchanges.length === 1 &&
firstSwapExchange && firstSwapExchange !== undefined &&
poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange) poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange)
) { ) {
options?.logger?.(`Swap is through pool [via ${firstSwapExchange}] (detected by "exchanges" field)`); options?.logger?.(`Swap is through pool [via ${firstSwapExchange}] (detected by "exchanges" field)`);
@@ -184,14 +189,14 @@ export default async function swapMarket({
if (route === 'pool') { if (route === 'pool') {
let factoryAddress: string | undefined; let factoryAddress: string | undefined;
if (factories && firstSwapExchange) { if (factories && firstSwapExchange !== undefined) {
factoryAddress = factories?.[firstSwapExchange]; factoryAddress = factories[firstSwapExchange];
if (factoryAddress) options?.logger?.(`Factory address is ${factoryAddress}. Exchange is ${firstSwapExchange}`); if (factoryAddress !== undefined) options?.logger?.(`Factory address is ${factoryAddress}. Exchange is ${firstSwapExchange}`);
} }
const pathAddresses = swapInfo.path.map((name) => { const pathAddresses = swapInfo.path.map((name) => {
const assetAddress = assetToAddress?.[name]; const assetAddress = assetToAddress[name];
if (!assetAddress) throw new Error(`No asset address for ${name}`); if (assetAddress === undefined) throw new Error(`No asset address for ${name}`);
return assetAddress; return assetAddress;
}); });
@@ -216,12 +221,12 @@ export default async function swapMarket({
}); });
const amountReceive = swapInfo.type === 'exactReceive' ? swapInfo.amountOut : amountOutWithSlippage; const amountReceive = swapInfo.type === 'exactReceive' ? swapInfo.amountOut : amountOutWithSlippage;
const amountSpendBlockchainParam = utils.normalizeNumber( const amountSpendBlockchainParam = normalizeNumber(
amountSpend, amountSpend,
INTERNAL_ORION_PRECISION, INTERNAL_ORION_PRECISION,
BigNumber.ROUND_CEIL, BigNumber.ROUND_CEIL,
); );
const amountReceiveBlockchainParam = utils.normalizeNumber( const amountReceiveBlockchainParam = normalizeNumber(
amountReceive, amountReceive,
INTERNAL_ORION_PRECISION, INTERNAL_ORION_PRECISION,
BigNumber.ROUND_FLOOR, BigNumber.ROUND_FLOOR,
@@ -229,7 +234,9 @@ export default async function swapMarket({
const unsignedSwapThroughOrionPoolTx = await exchangeContract.populateTransaction.swapThroughOrionPool( const unsignedSwapThroughOrionPoolTx = await exchangeContract.populateTransaction.swapThroughOrionPool(
amountSpendBlockchainParam, amountSpendBlockchainParam,
amountReceiveBlockchainParam, amountReceiveBlockchainParam,
factoryAddress ? [factoryAddress, ...pathAddresses] : pathAddresses, factoryAddress !== undefined
? [factoryAddress, ...pathAddresses]
: pathAddresses,
type === 'exactSpend', type === 'exactSpend',
); );
@@ -241,11 +248,11 @@ export default async function swapMarket({
let value = new BigNumber(0); let value = new BigNumber(0);
const denormalizedAssetInExchangeBalance = balances[assetIn]?.exchange; 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)) { if (assetIn === nativeCryptocurrency && amountSpendBN.gt(denormalizedAssetInExchangeBalance)) {
value = amountSpendBN.minus(denormalizedAssetInExchangeBalance); value = amountSpendBN.minus(denormalizedAssetInExchangeBalance);
} }
unsignedSwapThroughOrionPoolTx.value = utils.normalizeNumber( unsignedSwapThroughOrionPoolTx.value = normalizeNumber(
value.dp(INTERNAL_ORION_PRECISION, BigNumber.ROUND_CEIL), value.dp(INTERNAL_ORION_PRECISION, BigNumber.ROUND_CEIL),
NATIVE_CURRENCY_PRECISION, NATIVE_CURRENCY_PRECISION,
BigNumber.ROUND_CEIL, BigNumber.ROUND_CEIL,
@@ -253,7 +260,7 @@ export default async function swapMarket({
unsignedSwapThroughOrionPoolTx.gasLimit = ethers.BigNumber.from(SWAP_THROUGH_ORION_POOL_GAS_LIMIT); 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 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({ balanceGuard.registerRequirement({
reason: 'Network fee', reason: 'Network fee',
@@ -305,9 +312,9 @@ export default async function swapMarket({
.toString(); .toString();
const baseAssetAddress = assetToAddress[baseAssetName]; 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]; 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) const safePriceWithAppliedPrecision = new BigNumber(safePriceWithDeviation)
.decimalPlaces( .decimalPlaces(
@@ -331,16 +338,16 @@ export default async function swapMarket({
}); });
// Fee calculation // Fee calculation
const baseAssetPriceInOrn = pricesInOrn?.[baseAssetAddress]; const baseAssetPriceInOrn = pricesInOrn[baseAssetAddress];
if (!baseAssetPriceInOrn) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); if (baseAssetPriceInOrn === undefined) throw new Error(`Base asset price ${baseAssetName} in ORN not found`);
const baseCurrencyPriceInOrn = pricesInOrn[ethers.constants.AddressZero]; 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]; const feeAssetPriceInOrn = pricesInOrn[feeAssetAddress];
if (!feeAssetPriceInOrn) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); if (feeAssetPriceInOrn === undefined) throw new Error(`Fee asset price ${feeAsset} in ORN not found`);
const feePercent = feeAssets?.[feeAsset]; const feePercent = feeAssets[feeAsset];
if (!feePercent) throw new Error(`Fee asset ${feeAsset} not available`); 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, swapInfo.orderInfo.amount,
feeAssetPriceInOrn, feeAssetPriceInOrn,
baseAssetPriceInOrn, baseAssetPriceInOrn,
@@ -380,7 +387,7 @@ export default async function swapMarket({
await balanceGuard.check(options?.autoApprove); await balanceGuard.check(options?.autoApprove);
const signedOrder = await crypt.signOrder( const signedOrder = await signOrder(
baseAssetAddress, baseAssetAddress,
quoteAssetAddress, quoteAssetAddress,
swapInfo.orderInfo.side, swapInfo.orderInfo.side,

View File

@@ -1,23 +1,21 @@
/* eslint-disable max-len */
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Exchange__factory } from '@orionprotocol/contracts'; import { Exchange__factory } from '@orionprotocol/contracts';
import getBalances from '../../utils/getBalances'; import getBalances from '../../utils/getBalances';
import BalanceGuard from '../../BalanceGuard'; import BalanceGuard from '../../BalanceGuard';
import OrionUnit from '..'; import type OrionUnit from '..';
import { utils } from '../..';
import { import {
INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, WITHDRAW_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, WITHDRAW_GAS_LIMIT,
} from '../../constants'; } from '../../constants';
import { normalizeNumber } from '../../utils'; import { denormalizeNumber, normalizeNumber } from '../../utils';
import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency';
import simpleFetch from '../../simpleFetch'; import simpleFetch from '../../simpleFetch';
export type WithdrawParams = { export type WithdrawParams = {
asset: string, asset: string
amount: BigNumber.Value, amount: BigNumber.Value
signer: ethers.Signer, signer: ethers.Signer
orionUnit: OrionUnit, orionUnit: OrionUnit
} }
export default async function withdraw({ export default async function withdraw({
@@ -29,8 +27,8 @@ export default async function withdraw({
if (asset === '') throw new Error('Asset can not be empty'); if (asset === '') throw new Error('Asset can not be empty');
const amountBN = new BigNumber(amount); const amountBN = new BigNumber(amount);
if (amountBN.isNaN()) throw new Error(`Amount '${amount.toString()}' is not a number`); if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`);
if (amountBN.lte(0)) throw new Error(`Amount '${amount.toString()}' should be greater than 0`); if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`);
const walletAddress = await signer.getAddress(); const walletAddress = await signer.getAddress();
@@ -47,7 +45,7 @@ export default async function withdraw({
const gasPriceWei = await simpleFetch(orionBlockchain.getGasPriceWei)(); const gasPriceWei = await simpleFetch(orionBlockchain.getGasPriceWei)();
const assetAddress = assetToAddress[asset]; 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( const balances = await getBalances(
{ {
@@ -76,7 +74,7 @@ export default async function withdraw({
name: asset, name: asset,
address: assetAddress, address: assetAddress,
}, },
amount: amount.toString(), amount: amountBN.toString(),
sources: ['exchange'], sources: ['exchange'],
}); });
@@ -87,7 +85,7 @@ export default async function withdraw({
unsignedTx.gasLimit = ethers.BigNumber.from(WITHDRAW_GAS_LIMIT); unsignedTx.gasLimit = ethers.BigNumber.from(WITHDRAW_GAS_LIMIT);
const transactionCost = ethers.BigNumber.from(unsignedTx.gasLimit).mul(gasPriceWei); 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({ balanceGuard.registerRequirement({
reason: 'Network fee', reason: 'Network fee',
@@ -112,7 +110,7 @@ export default async function withdraw({
const txResponse = await provider.sendTransaction(signedTx); const txResponse = await provider.sendTransaction(signedTx);
console.log(`Withdraw tx sent: ${txResponse.hash}. Waiting for confirmation...`); console.log(`Withdraw tx sent: ${txResponse.hash}. Waiting for confirmation...`);
const txReceipt = await txResponse.wait(); const txReceipt = await txResponse.wait();
if (txReceipt.status) { if (txReceipt.status !== undefined) {
console.log('Withdraw tx confirmed'); console.log('Withdraw tx confirmed');
} else { } else {
console.log('Withdraw tx failed'); console.log('Withdraw tx failed');

View File

@@ -1,7 +1,7 @@
import { Exchange__factory, IUniswapV2Pair__factory, IUniswapV2Router__factory } from '@orionprotocol/contracts'; import { Exchange__factory, IUniswapV2Pair__factory, IUniswapV2Router__factory } from '@orionprotocol/contracts';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import OrionUnit from '..'; import type OrionUnit from '..';
import BalanceGuard from '../../BalanceGuard'; import BalanceGuard from '../../BalanceGuard';
import { ADD_LIQUIDITY_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION } from '../../constants'; import { ADD_LIQUIDITY_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION } from '../../constants';
import simpleFetch from '../../simpleFetch'; import simpleFetch from '../../simpleFetch';
@@ -12,14 +12,14 @@ import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency';
const ADD_LIQUIDITY_SLIPPAGE = 0.05; const ADD_LIQUIDITY_SLIPPAGE = 0.05;
export type AddLiquidityParams = { export type AddLiquidityParams = {
poolName: string, poolName: string
amountAsset: string, amountAsset: string
amount: BigNumber.Value, amount: BigNumber.Value
signer: ethers.Signer signer: ethers.Signer
} }
export type RemoveAllLiquidityParams = { export type RemoveAllLiquidityParams = {
poolName: string, poolName: string
signer: ethers.Signer signer: ethers.Signer
} }
@@ -57,14 +57,14 @@ export default class FarmingManager {
.connect(exchangeContractAddress, this.orionUnit.provider); .connect(exchangeContractAddress, this.orionUnit.provider);
const assetAAddress = assetToAddress[assetA]; 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]; 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]; 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]; 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 nativeCryptocurrency = getNativeCryptocurrency(assetToAddress);
const balances = await getBalances( const balances = await getBalances(
@@ -145,7 +145,7 @@ export default class FarmingManager {
sources: ['exchange', 'wallet'], sources: ['exchange', 'wallet'],
}); });
const unsignedTx = await exchangeContract?.populateTransaction.withdrawToPool( const unsignedTx = await exchangeContract.populateTransaction.withdrawToPool(
assetBIsNativeCurrency ? assetBAddress : assetAAddress, assetBIsNativeCurrency ? assetBAddress : assetAAddress,
assetBIsNativeCurrency ? assetAAddress : assetBAddress, assetBIsNativeCurrency ? assetAAddress : assetBAddress,
assetBIsNativeCurrency assetBIsNativeCurrency
@@ -231,14 +231,14 @@ export default class FarmingManager {
} = await simpleFetch(this.orionUnit.orionBlockchain.getInfo)(); } = await simpleFetch(this.orionUnit.orionBlockchain.getInfo)();
const assetAAddress = assetToAddress[assetA]; 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]; 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]; 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]; 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 poolsConfig = await simpleFetch(this.orionUnit.orionBlockchain.getPoolsConfig)();
const pool = poolsConfig.pools[poolName]; const pool = poolsConfig.pools[poolName];

View File

@@ -6,7 +6,7 @@ import type { SupportedChainId, VerboseOrionUnitConfig } from '../types';
import Exchange from './Exchange'; import Exchange from './Exchange';
import FarmingManager from './FarmingManager'; import FarmingManager from './FarmingManager';
import { chains } from '../config'; import { chains } from '../config';
import { networkCodes } from '../constants'; import { type networkCodes } from '../constants';
// type KnownConfig = { // type KnownConfig = {
// env: string; // env: string;

View File

@@ -8,14 +8,23 @@ import express from 'express';
import WebSocket from 'ws'; import WebSocket from 'ws';
import http from 'http'; import http from 'http';
import httpToWS from '../utils/httpToWS'; import httpToWS from '../utils/httpToWS';
import {
createHttpTerminator,
} from 'http-terminator';
jest.setTimeout(10000);
const createServer = (externalHost: string) => { const createServer = (externalHost: string) => {
const app = express(); const app = express();
const server = http.createServer(app); const server = http.createServer(app);
const httpTerminator = createHttpTerminator({ server });
const wss = new WebSocket.Server({ server }); const wss = new WebSocket.Server({ server });
let externalWs: WebSocket | null = null; let externalWs: WebSocket | null = null;
wss.on('connection', (ws, req) => { wss.on('connection', (ws, req) => {
if (req.url === undefined) throw new Error('req.url is undefined');
const targetUrl = httpToWS(`${externalHost}${req.url}`); const targetUrl = httpToWS(`${externalHost}${req.url}`);
externalWs = new WebSocket(targetUrl); externalWs = new WebSocket(targetUrl);
@@ -32,7 +41,8 @@ const createServer = (externalHost: string) => {
app.get( app.get(
'*', '*',
async (req, res) => { (req, res) => {
(async () => {
const routeFromURL = req.url; const routeFromURL = req.url;
try { try {
const targetUrl = `${externalHost}${routeFromURL}`; const targetUrl = `${externalHost}${routeFromURL}`;
@@ -44,21 +54,27 @@ const createServer = (externalHost: string) => {
error: 'Failed to retrieve data from external resource' error: 'Failed to retrieve data from external resource'
}); });
} }
})().catch(console.error)
}); });
server.listen(0); server.listen(0);
const address = server.address(); const address = server.address();
if (typeof address === 'string') { if (typeof address === 'string') {
throw new Error(`Server address is a string: ${address}`); throw new Error(`Server address is a string: ${address}`);
} }
const closeWS = () => new Promise((resolve) => {
wss.close(resolve);
});
return { return {
port: address?.port, port: address?.port,
close: () => new Promise((resolve) => { terminate: async () => {
externalWs?.close(); externalWs?.close();
server.close(resolve); await closeWS();
}), await httpTerminator.terminate();
}
} }
} }
@@ -137,6 +153,10 @@ describe('Orion', () => {
const server1 = createServer('https://trade.orionprotocol.io'); const server1 = createServer('https://trade.orionprotocol.io');
const server2 = 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 orionBlockchainAPI = `http://localhost:${server0.port}`;
const orionAggregatorAPI = `http://localhost:${server1.port}`; const orionAggregatorAPI = `http://localhost:${server1.port}`;
const orionPriceFeedAPI = `http://localhost:${server2.port}`; const orionPriceFeedAPI = `http://localhost:${server2.port}`;
@@ -165,7 +185,7 @@ describe('Orion', () => {
} }
}); });
const orionUnit = orion.unitsArray[0]; const [orionUnit] = orion.unitsArray;
if (!orionUnit) { if (!orionUnit) {
throw new Error('Orion unit is not defined'); throw new Error('Orion unit is not defined');
} }
@@ -197,10 +217,6 @@ describe('Orion', () => {
expect(priceData).toBeDefined(); expect(priceData).toBeDefined();
const allTickersDone = await new Promise<boolean>((resolve, reject) => { const allTickersDone = await new Promise<boolean>((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Timeout'));
}, 10000);
const { unsubscribe } = orionUnit.priceFeed.ws.subscribe( const { unsubscribe } = orionUnit.priceFeed.ws.subscribe(
'allTickers', 'allTickers',
{ {
@@ -211,12 +227,16 @@ describe('Orion', () => {
} }
} }
) )
const timeout = setTimeout(() => {
unsubscribe();
reject(new Error(`Timeout: ${orionUnit.priceFeed.wsUrl}`));
}, 10000);
}); });
expect(allTickersDone).toBe(true); expect(allTickersDone).toBe(true);
await server0.close(); await server0.terminate();
await server1.close(); await server1.terminate();
await server2.close(); await server2.terminate();
}); });
test('Init Orion testing with overrides', () => { test('Init Orion testing with overrides', () => {

View File

@@ -1,4 +1,4 @@
import exchanges from './exchanges'; import type exchanges from './exchanges';
const mapping: Record< const mapping: Record<
typeof exchanges[number], 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 eip712DomainData from '../config/eip712DomainData.json';
import eip712DomainSchema from '../config/schemas/eip712DomainSchema'; import eip712DomainSchema from '../config/schemas/eip712DomainSchema';

View File

@@ -1,5 +1,5 @@
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { CFDOrder } from '../types'; import { type CFDOrder } from '../types';
const hashCFDOrder = (order: CFDOrder) => ethers.utils.solidityKeccak256( const hashCFDOrder = (order: CFDOrder) => ethers.utils.solidityKeccak256(
[ [
@@ -24,7 +24,7 @@ const hashCFDOrder = (order: CFDOrder) => ethers.utils.solidityKeccak256(
order.matcherFee, order.matcherFee,
order.nonce, order.nonce,
order.expiration, order.expiration,
order.buySide ? '0x01' : '0x00', order.buySide === 1 ? '0x01' : '0x00',
], ],
); );

View File

@@ -1,5 +1,5 @@
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Order } from '../types'; import { type Order } from '../types';
const hashOrder = (order: Order) => ethers.utils.solidityKeccak256( const hashOrder = (order: Order) => ethers.utils.solidityKeccak256(
[ [
@@ -28,7 +28,7 @@ const hashOrder = (order: Order) => ethers.utils.solidityKeccak256(
order.matcherFee, order.matcherFee,
order.nonce, order.nonce,
order.expiration, order.expiration,
order.buySide ? '0x01' : '0x00', order.buySide === 1 ? '0x01' : '0x00',
], ],
); );

View File

@@ -1,10 +1,9 @@
/* eslint-disable no-underscore-dangle */ import { type TypedDataSigner } from '@ethersproject/abstract-signer';
import { TypedDataSigner } from '@ethersproject/abstract-signer';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { type ethers } from 'ethers';
import { joinSignature, splitSignature } from 'ethers/lib/utils'; import { joinSignature, splitSignature } from 'ethers/lib/utils';
import { INTERNAL_ORION_PRECISION } from '../constants'; 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 normalizeNumber from '../utils/normalizeNumber';
import getDomainData from './getDomainData'; import getDomainData from './getDomainData';
import signCFDOrderPersonal from './signCFDOrderPersonal'; 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" // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1"
const fixedSignature = joinSignature(splitSignature(signature)); 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 = { const signedOrder: SignedCFDOrder = {
...order, ...order,

View File

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

View File

@@ -1,9 +1,8 @@
/* eslint-disable no-underscore-dangle */ import { type TypedDataSigner } from '@ethersproject/abstract-signer';
import { TypedDataSigner } from '@ethersproject/abstract-signer'; import { type ethers } from 'ethers';
import { ethers } from 'ethers';
import { joinSignature, splitSignature } from 'ethers/lib/utils'; import { joinSignature, splitSignature } from 'ethers/lib/utils';
import CANCEL_ORDER_TYPES from '../constants/cancelOrderTypes'; 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 getDomainData from './getDomainData';
import signCancelOrderPersonal from './signCancelOrderPersonal'; 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" // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1"
const fixedSignature = joinSignature(splitSignature(signature)); 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 = { const signedCancelOrderReqeust: SignedCancelOrderRequest = {
...cancelOrderRequest, ...cancelOrderRequest,

View File

@@ -1,6 +1,6 @@
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { arrayify, joinSignature, splitSignature } from 'ethers/lib/utils'; import { arrayify, joinSignature, splitSignature } from 'ethers/lib/utils';
import { CancelOrderRequest } from '../types'; import { type CancelOrderRequest } from '../types';
const signCancelOrderPersonal = async ( const signCancelOrderPersonal = async (
cancelOrderRequest: CancelOrderRequest, cancelOrderRequest: CancelOrderRequest,

View File

@@ -1,11 +1,10 @@
/* eslint-disable no-underscore-dangle */ import { type TypedDataSigner } from '@ethersproject/abstract-signer';
import { TypedDataSigner } from '@ethersproject/abstract-signer';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { type ethers } from 'ethers';
import { joinSignature, splitSignature } from 'ethers/lib/utils'; import { joinSignature, splitSignature } from 'ethers/lib/utils';
import { INTERNAL_ORION_PRECISION } from '../constants'; import { INTERNAL_ORION_PRECISION } from '../constants';
import ORDER_TYPES from '../constants/orderTypes'; 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 normalizeNumber from '../utils/normalizeNumber';
import getDomainData from './getDomainData'; import getDomainData from './getDomainData';
import hashOrder from './hashOrder'; 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" // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1"
const fixedSignature = joinSignature(splitSignature(signature)); 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 = { const signedOrder: SignedOrder = {
...order, ...order,

View File

@@ -1,5 +1,5 @@
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Order } from '../types'; import { type Order } from '../types';
const { arrayify, joinSignature, splitSignature } = ethers.utils; 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 fetch from 'isomorphic-unfetch';
import { import {
@@ -26,7 +26,7 @@ export default async function fetchWithValidation<DataOut, DataIn, ErrorOut, Err
// payload // payload
const fetchResult = await fromPromise(fetch(url, { const fetchResult = await fromPromise(fetch(url, {
...options || {}, ...options ?? {},
headers: { headers: {
'Cache-Control': 'no-store, max-age=0', 'Cache-Control': 'no-store, max-age=0',
...(options ? options.headers : {}), ...(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 { z } from 'zod';
import fetchWithValidation from '../../fetchWithValidation'; import fetchWithValidation from '../../fetchWithValidation';
import swapInfoSchema from './schemas/swapInfoSchema'; import swapInfoSchema from './schemas/swapInfoSchema';
@@ -9,12 +9,12 @@ import errorSchema from './schemas/errorSchema';
import placeAtomicSwapSchema from './schemas/placeAtomicSwapSchema'; import placeAtomicSwapSchema from './schemas/placeAtomicSwapSchema';
import { OrionAggregatorWS } from './ws'; import { OrionAggregatorWS } from './ws';
import { atomicSwapHistorySchema } from './schemas/atomicSwapHistorySchema'; 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 { pairConfigSchema } from './schemas';
import { import {
aggregatedOrderbookSchema, exchangeOrderbookSchema, poolReservesSchema, aggregatedOrderbookSchema, exchangeOrderbookSchema, poolReservesSchema,
} from './schemas/aggregatedOrderbookSchema'; } from './schemas/aggregatedOrderbookSchema';
import networkCodes from '../../constants/networkCodes'; import type networkCodes from '../../constants/networkCodes';
import toUpperCase from '../../utils/toUpperCase'; import toUpperCase from '../../utils/toUpperCase';
import httpToWS from '../../utils/httpToWS'; import httpToWS from '../../utils/httpToWS';
@@ -146,7 +146,7 @@ class OrionAggregator {
const headers = { const headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
Accept: 'application/json', Accept: 'application/json',
...partnerId && { 'X-Partner-Id': partnerId }, ...(partnerId !== undefined) && { 'X-Partner-Id': partnerId },
}; };
return fetchWithValidation( return fetchWithValidation(
@@ -232,7 +232,7 @@ class OrionAggregator {
} else { } else {
url.searchParams.append('amountOut', amount); url.searchParams.append('amountOut', amount);
} }
if (exchanges) { if (exchanges !== undefined) {
if (Array.isArray(exchanges)) { if (Array.isArray(exchanges)) {
exchanges.forEach((exchange) => { exchanges.forEach((exchange) => {
url.searchParams.append('exchanges', exchange); url.searchParams.append('exchanges', exchange);
@@ -241,7 +241,7 @@ class OrionAggregator {
url.searchParams.append('exchanges', exchanges); url.searchParams.append('exchanges', exchanges);
} }
} }
if (instantSettlement) { if (instantSettlement !== undefined && instantSettlement) {
url.searchParams.append('instantSettlement', 'true'); url.searchParams.append('instantSettlement', 'true');
} }

View File

@@ -10,12 +10,12 @@ import {
} from './schemas'; } from './schemas';
import UnsubscriptionType from './UnsubscriptionType'; import UnsubscriptionType from './UnsubscriptionType';
import { import {
SwapInfoBase, AssetPairUpdate, OrderbookItem, Balance, type SwapInfoBase, type AssetPairUpdate, type OrderbookItem,
Exchange, CFDBalance, SwapInfo, FuturesTradeInfo, type Balance, type Exchange, type CFDBalance, type FuturesTradeInfo, type SwapInfo,
} from '../../../types'; } from '../../../types';
import unsubscriptionDoneSchema from './schemas/unsubscriptionDoneSchema'; import unsubscriptionDoneSchema from './schemas/unsubscriptionDoneSchema';
import assetPairConfigSchema from './schemas/assetPairConfigSchema'; 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 cfdAddressUpdateSchema from './schemas/cfdAddressUpdateSchema';
import futuresTradeInfoSchema from './schemas/futuresTradeInfoSchema'; import futuresTradeInfoSchema from './schemas/futuresTradeInfoSchema';
// import errorSchema from './schemas/errorSchema'; // 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 // https://github.com/orionprotocol/orion-aggregator/tree/feature/OP-1752-symmetric-swap#swap-info-subscribe
type SwapSubscriptionRequest = { type SwapSubscriptionRequest = {
// d: string, // swap request UUID, set by client side // d: string, // swap request UUID, set by client side
i: string, // asset in i: string // asset in
o: string, // asset out o: string // asset out
a: number // amount IN/OUT a: number // amount IN/OUT
es?: Exchange[] | 'cex' | 'pools', // exchange list of all cex or all pools (ORION_POOL, UNISWAP, PANCAKESWAP etc) 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 e?: boolean // is amount IN? Value `false` means a = amount OUT, `true` if omitted
is?: boolean; // instant settlement is?: boolean // instant settlement
} }
type BrokerTradableAtomicSwapBalanceSubscription = { type BrokerTradableAtomicSwapBalanceSubscription = {
callback: (balances: Partial<Record<string, number>>) => void, callback: (balances: Partial<Record<string, number>>) => void
} }
type PairsConfigSubscription = { type PairsConfigSubscription = {
callback: ({ kind, data }: { callback: ({ kind, data }: {
kind: 'initial' | 'update', kind: 'initial' | 'update'
data: Partial<Record<string, AssetPairUpdate>>, data: Partial<Record<string, AssetPairUpdate>>
}) => void, }) => void
} }
type PairConfigSubscription = { type PairConfigSubscription = {
payload: string, payload: string
callback: ({ kind, data }: { callback: ({ kind, data }: {
kind: 'initial' | 'update', kind: 'initial' | 'update'
data: AssetPairUpdate, data: AssetPairUpdate
}) => void, }) => void
} }
type AggregatedOrderbookSubscription = { type AggregatedOrderbookSubscription = {
payload: string, payload: string
callback: ( callback: (
asks: OrderbookItem[], asks: OrderbookItem[],
bids: OrderbookItem[], bids: OrderbookItem[],
pair: string pair: string
) => void, ) => void
} }
type SwapInfoSubscription = { type SwapInfoSubscription = {
payload: SwapSubscriptionRequest, payload: SwapSubscriptionRequest
callback: (swapInfo: SwapInfo) => void, callback: (swapInfo: SwapInfo) => void
} }
type FuturesTradeInfoSubscription = { type FuturesTradeInfoSubscription = {
payload: { payload: {
s: string, s: string
i: string, i: string
a: number, a: number
p?: number, p?: number
}, }
callback: (futuresTradeInfo: FuturesTradeInfo) => void, callback: (futuresTradeInfo: FuturesTradeInfo) => void
} }
type AddressUpdateUpdate = { type AddressUpdateUpdate = {
kind: 'update', kind: 'update'
balances: Partial< balances: Partial<
Record< Record<
string, string,
Balance Balance
> >
>, >
order?: z.infer<typeof orderUpdateSchema> | z.infer<typeof fullOrderSchema> order?: z.infer<typeof orderUpdateSchema> | z.infer<typeof fullOrderSchema>
} }
type AddressUpdateInitial = { type AddressUpdateInitial = {
kind: 'initial', kind: 'initial'
balances: Partial< balances: Partial<
Record< Record<
string, string,
Balance Balance
> >
>, >
orders?: z.infer<typeof fullOrderSchema>[] // The field is not defined if the user has no orders orders?: Array<z.infer<typeof fullOrderSchema>> // The field is not defined if the user has no orders
} }
type CfdAddressUpdateUpdate = { type CfdAddressUpdateUpdate = {
kind: 'update', kind: 'update'
balances?: CFDBalance[], balances?: CFDBalance[]
order?: z.infer<typeof orderUpdateSchema> | z.infer<typeof fullOrderSchema> order?: z.infer<typeof orderUpdateSchema> | z.infer<typeof fullOrderSchema>
} }
type CfdAddressUpdateInitial = { type CfdAddressUpdateInitial = {
kind: 'initial', kind: 'initial'
balances: CFDBalance[], balances: CFDBalance[]
orders?: z.infer<typeof fullOrderSchema>[] // The field is not defined if the user has no orders orders?: Array<z.infer<typeof fullOrderSchema>> // The field is not defined if the user has no orders
} }
type AddressUpdateSubscription = { type AddressUpdateSubscription = {
payload: string, payload: string
callback: (data: AddressUpdateUpdate | AddressUpdateInitial) => void, callback: (data: AddressUpdateUpdate | AddressUpdateInitial) => void
} }
type CfdAddressUpdateSubscription = { type CfdAddressUpdateSubscription = {
payload: string, payload: string
callback: (data: CfdAddressUpdateUpdate | CfdAddressUpdateInitial) => void, callback: (data: CfdAddressUpdateUpdate | CfdAddressUpdateInitial) => void
} }
type Subscription = { type Subscription = {
[SubscriptionType.ADDRESS_UPDATES_SUBSCRIBE]: AddressUpdateSubscription, [SubscriptionType.ADDRESS_UPDATES_SUBSCRIBE]: AddressUpdateSubscription
[SubscriptionType.CFD_ADDRESS_UPDATES_SUBSCRIBE]: CfdAddressUpdateSubscription, [SubscriptionType.CFD_ADDRESS_UPDATES_SUBSCRIBE]: CfdAddressUpdateSubscription
[SubscriptionType.AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE]: AggregatedOrderbookSubscription, [SubscriptionType.AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE]: AggregatedOrderbookSubscription
[SubscriptionType.ASSET_PAIRS_CONFIG_UPDATES_SUBSCRIBE]: PairsConfigSubscription, [SubscriptionType.ASSET_PAIRS_CONFIG_UPDATES_SUBSCRIBE]: PairsConfigSubscription
[SubscriptionType.ASSET_PAIR_CONFIG_UPDATES_SUBSCRIBE]: PairConfigSubscription, [SubscriptionType.ASSET_PAIR_CONFIG_UPDATES_SUBSCRIBE]: PairConfigSubscription
[SubscriptionType.BROKER_TRADABLE_ATOMIC_SWAP_ASSETS_BALANCE_UPDATES_SUBSCRIBE]: BrokerTradableAtomicSwapBalanceSubscription, [SubscriptionType.BROKER_TRADABLE_ATOMIC_SWAP_ASSETS_BALANCE_UPDATES_SUBSCRIBE]: BrokerTradableAtomicSwapBalanceSubscription
[SubscriptionType.SWAP_SUBSCRIBE]: SwapInfoSubscription [SubscriptionType.SWAP_SUBSCRIBE]: SwapInfoSubscription
[SubscriptionType.FUTURES_TRADE_INFO_SUBSCRIBE]: FuturesTradeInfoSubscription [SubscriptionType.FUTURES_TRADE_INFO_SUBSCRIBE]: FuturesTradeInfoSubscription
} }
@@ -145,14 +145,14 @@ type BufferLike =
| Uint8Array | Uint8Array
| ArrayBuffer | ArrayBuffer
| SharedArrayBuffer | SharedArrayBuffer
| ReadonlyArray<unknown> | readonly unknown[]
| ReadonlyArray<number> | readonly number[]
| { valueOf(): ArrayBuffer } | { valueOf: () => ArrayBuffer }
| { valueOf(): SharedArrayBuffer } | { valueOf: () => SharedArrayBuffer }
| { valueOf(): Uint8Array } | { valueOf: () => Uint8Array }
| { valueOf(): ReadonlyArray<number> } | { valueOf: () => readonly number[] }
| { valueOf(): string } | { valueOf: () => string }
| { [Symbol.toPrimitive](hint: string): string }; | { [Symbol.toPrimitive]: (hint: string) => string };
const isSubType = (subType: string): subType is keyof Subscription => Object.values(SubscriptionType).some((t) => t === subType); const isSubType = (subType: string): subType is keyof Subscription => Object.values(SubscriptionType).some((t) => t === subType);
class OrionAggregatorWS { class OrionAggregatorWS {
@@ -339,8 +339,9 @@ class OrionAggregatorWS {
}; };
this.ws.onmessage = (e) => { this.ws.onmessage = (e) => {
const { data } = e; const { data } = e;
this.logger?.(`OrionAggregatorWS: received message: ${e.data.toString()}`); if (typeof data !== 'string') throw new Error('OrionAggregatorWS: received non-string message');
const rawJson: unknown = JSON.parse(data.toString()); this.logger?.(`OrionAggregatorWS: received message: ${data}`);
const rawJson: unknown = JSON.parse(data);
const messageSchema = z.union([ const messageSchema = z.union([
initMessageSchema, initMessageSchema,
@@ -385,7 +386,7 @@ class OrionAggregatorWS {
path: json.ps, path: json.ps,
exchanges: json.e, exchanges: json.e,
poolOptimal: json.po, poolOptimal: json.po,
...json.oi && { ...(json.oi) && {
orderInfo: { orderInfo: {
pair: json.oi.p, pair: json.oi.p,
side: json.oi.s, side: json.oi.s,
@@ -511,8 +512,8 @@ class OrionAggregatorWS {
case MessageType.CFD_ADDRESS_UPDATE: case MessageType.CFD_ADDRESS_UPDATE:
switch (json.k) { // message kind switch (json.k) { // message kind
case 'i': { // initial case 'i': { // initial
const fullOrders = json.o 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); prev.push(o);
return prev; return prev;
@@ -524,7 +525,7 @@ class OrionAggregatorWS {
]?.[json.id]?.callback({ ]?.[json.id]?.callback({
kind: 'initial', kind: 'initial',
orders: fullOrders, orders: fullOrders,
balances: json.b ?? [], balances: json.b,
}); });
} }
break; break;
@@ -549,7 +550,7 @@ class OrionAggregatorWS {
} }
break; break;
case MessageType.ADDRESS_UPDATE: { case MessageType.ADDRESS_UPDATE: {
const balances = json.b const balances = (json.b)
? Object.entries(json.b) ? Object.entries(json.b)
.reduce<Partial<Record<string, Balance>>>((prev, [asset, assetBalances]) => { .reduce<Partial<Record<string, Balance>>>((prev, [asset, assetBalances]) => {
if (!assetBalances) return prev; if (!assetBalances) return prev;
@@ -565,7 +566,7 @@ class OrionAggregatorWS {
switch (json.k) { // message kind switch (json.k) { // message kind
case 'i': { // initial case 'i': { // initial
const fullOrders = json.o 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); prev.push(o);
return prev; return prev;

View File

@@ -2,7 +2,7 @@ import fetchWithValidation from '../../fetchWithValidation';
import overviewSchema from './schemas/overviewSchema'; import overviewSchema from './schemas/overviewSchema';
export default class OrionAnalytics { export default class OrionAnalytics {
private apiUrl: string; private readonly apiUrl: string;
constructor(apiUrl: string) { constructor(apiUrl: string) {
this.apiUrl = apiUrl; this.apiUrl = apiUrl;

View File

@@ -3,63 +3,63 @@ import fetchWithValidation from '../../fetchWithValidation';
import { import {
IDOSchema, atomicHistorySchema, IDOSchema, atomicHistorySchema,
poolsConfigSchema, poolsInfoSchema, infoSchema, historySchema, poolsConfigSchema, poolsInfoSchema, infoSchema, historySchema,
addPoolSchema, adminPoolsListSchema, adminPoolSchema, type addPoolSchema, adminPoolsListSchema, adminPoolSchema,
atomicSummarySchema, atomicSummarySchema,
poolsLpAndStakedSchema, poolsLpAndStakedSchema,
userVotesSchema, userVotesSchema,
userEarnedSchema, userEarnedSchema,
PairStatusEnum, type PairStatusEnum,
pairStatusSchema, pairStatusSchema,
cfdContractsSchema, cfdContractsSchema,
cfdHistorySchema, cfdHistorySchema,
} from './schemas'; } from './schemas';
import redeemOrderSchema from '../OrionAggregator/schemas/redeemOrderSchema'; import type redeemOrderSchema from '../OrionAggregator/schemas/redeemOrderSchema';
import { sourceAtomicHistorySchema, targetAtomicHistorySchema } from './schemas/atomicHistorySchema'; import { sourceAtomicHistorySchema, targetAtomicHistorySchema } from './schemas/atomicHistorySchema';
import { makePartial } from '../../utils'; import { makePartial } from '../../utils';
import { networkCodes } from '../../constants'; import { type networkCodes } from '../../constants';
interface IAdminAuthHeaders { type IAdminAuthHeaders = {
auth: string; auth: string
[key: string]: string [key: string]: string
} }
export interface IEditPool { export type IEditPool = {
tokenAIcon?: string; tokenAIcon?: string
tokenBIcon?: string; tokenBIcon?: string
symbol?: string; symbol?: string
status: PairStatusEnum; status: PairStatusEnum
minQty?: number; minQty?: number
tokenASymbol?: string; tokenASymbol?: string
tokenBSymbol?: string; tokenBSymbol?: string
tokensReversed?: boolean; tokensReversed?: boolean
} }
type AtomicSwapHistoryBaseQuery = { type AtomicSwapHistoryBaseQuery = {
limit?: number limit?: number
sender?: string, sender?: string
receiver?: string, receiver?: string
used?: 0 | 1, used?: 0 | 1
page?: number, page?: number
sourceNetworkCode?: typeof networkCodes[number], sourceNetworkCode?: typeof networkCodes[number]
} } & Partial<Record<string, string | number>>
type AtomicSwapHistorySourceQuery = AtomicSwapHistoryBaseQuery & { type AtomicSwapHistorySourceQuery = AtomicSwapHistoryBaseQuery & {
type?: 'source', type?: 'source'
expiredLock?: 0 | 1, expiredLock?: 0 | 1
state?: 'LOCKED' | 'CLAIMED' |'REFUNDED', state?: 'LOCKED' | 'CLAIMED' | 'REFUNDED'
} }
type AtomicSwapHistoryTargetQuery = AtomicSwapHistoryBaseQuery & { type AtomicSwapHistoryTargetQuery = AtomicSwapHistoryBaseQuery & {
type?: 'target', type?: 'target'
expiredRedeem?: 0 | 1, expiredRedeem?: 0 | 1
state?: 'REDEEMED' | 'BEFORE-REDEEM', state?: 'REDEEMED' | 'BEFORE-REDEEM'
} }
type CfdHistoryQuery = { type CfdHistoryQuery = {
instrument?: string, instrument?: string
page?: number, page?: number
limit?: number, limit?: number
} } & Partial<Record<string, string | number>>
class OrionBlockchain { class OrionBlockchain {
private readonly apiUrl: string; private readonly apiUrl: string;
@@ -110,12 +110,12 @@ class OrionBlockchain {
return `${this.apiUrl}/`; 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}`); const url = new URL(`${this.apiUrl}/api/atomic/summary-redeem/${brokerAddress}`);
if (unshifted) { if (unshifted !== undefined && unshifted === 1) {
url.searchParams.append('unshifted', unshifted.toString()); url.searchParams.append('unshifted', unshifted.toString());
} }
if (sourceNetworkCode) { if (sourceNetworkCode !== undefined) {
url.searchParams.append('sourceNetworkCode', sourceNetworkCode); url.searchParams.append('sourceNetworkCode', sourceNetworkCode);
} }
return fetchWithValidation( 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}`, `${this.apiUrl}/api/atomic/summary-claim/${brokerAddress}`,
atomicSummarySchema, atomicSummarySchema,
); );
private getQueueLength = () => fetchWithValidation( private readonly getQueueLength = () => fetchWithValidation(
`${this.apiUrl}/api/queueLength`, `${this.apiUrl}/api/queueLength`,
z.number().int(), z.number().int(),
); );
@@ -357,7 +357,10 @@ class OrionBlockchain {
const url = new URL(`${this.apiUrl}/api/atomic/history/`); const url = new URL(`${this.apiUrl}/api/atomic/history/`);
Object.entries(query) 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); return fetchWithValidation(url.toString(), atomicHistorySchema);
}; };
@@ -366,9 +369,12 @@ class OrionBlockchain {
const url = new URL(`${this.apiUrl}/api/atomic/history/`); const url = new URL(`${this.apiUrl}/api/atomic/history/`);
Object.entries(query) 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); return fetchWithValidation(url.toString(), sourceAtomicHistorySchema);
}; };
@@ -377,9 +383,12 @@ class OrionBlockchain {
const url = new URL(`${this.apiUrl}/api/atomic/history/`); const url = new URL(`${this.apiUrl}/api/atomic/history/`);
Object.entries(query) 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); return fetchWithValidation(url.toString(), targetAtomicHistorySchema);
}; };
@@ -406,7 +415,10 @@ class OrionBlockchain {
const url = new URL(`${this.apiUrl}/api/cfd/deposit-withdraw/${address}`); const url = new URL(`${this.apiUrl}/api/cfd/deposit-withdraw/${address}`);
Object.entries(query) 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); return fetchWithValidation(url.toString(), cfdHistorySchema);
}; };

View File

@@ -1,11 +1,11 @@
import fetchWithValidation from '../../fetchWithValidation'; import fetchWithValidation from '../../fetchWithValidation';
import { Exchange } from '../../types'; import { type Exchange } from '../../types';
import { statisticsOverviewSchema, topPairsStatisticsSchema } from './schemas'; import { statisticsOverviewSchema, topPairsStatisticsSchema } from './schemas';
import candlesSchema from './schemas/candlesSchema'; import candlesSchema from './schemas/candlesSchema';
import { PriceFeedWS } from './ws'; import { PriceFeedWS } from './ws';
class PriceFeed { class PriceFeed {
private apiUrl: string; private readonly apiUrl: string;
readonly ws: PriceFeedWS; readonly ws: PriceFeedWS;

View File

@@ -6,12 +6,12 @@ import { tickerInfoSchema, candleSchema } from './schemas';
import priceSchema from './schemas/priceSchema'; import priceSchema from './schemas/priceSchema';
type TickerInfo = { type TickerInfo = {
pairName: string; pairName: string
lastPrice: string; lastPrice: string
openPrice: string; openPrice: string
highPrice: string; highPrice: string
lowPrice: string; lowPrice: string
volume24h: string; volume24h: string
} }
const allTickersSchema = z.unknown().array() const allTickersSchema = z.unknown().array()
@@ -57,10 +57,10 @@ export type Subscription<
Schema = z.infer<typeof subscriptions[T]['schema']> Schema = z.infer<typeof subscriptions[T]['schema']>
> = typeof subscriptions[T] extends { payload: true } > = typeof subscriptions[T] extends { payload: true }
? { ? {
callback: (data: Schema) => void, callback: (data: Schema) => void
payload: string, payload: string
} : { } : {
callback: (data: Schema) => void, callback: (data: Schema) => void
} }
export default class PriceFeedSubscription<T extends SubscriptionType = SubscriptionType> { export default class PriceFeedSubscription<T extends SubscriptionType = SubscriptionType> {
@@ -104,16 +104,23 @@ export default class PriceFeedSubscription<T extends SubscriptionType = Subscrip
this.isClosedIntentionally = false; this.isClosedIntentionally = false;
const { payload, url, type } = this; 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) => { this.ws.onmessage = (e) => {
if (e.data === 'pong') return; const { data } = e;
const json: unknown = JSON.parse(e.data.toString());
// 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 subscription = subscriptions[type];
const parseResult = subscription.schema.safeParse(json); 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(', '); 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); 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 * as schemas from './schemas';
export class PriceFeedWS { export class PriceFeedWS {
@@ -11,7 +11,7 @@ export class PriceFeedWS {
>; >;
}> = {}; }> = {};
private url: string; private readonly url: string;
constructor(url: string) { constructor(url: string) {
this.url = url; this.url = url;
@@ -36,7 +36,7 @@ export class PriceFeedWS {
return { return {
type: sub.type, type: sub.type,
id: sub.id, 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'; import linkSchema from './schemas/linkSchema';
type CreateLinkPayloadType = { type CreateLinkPayloadType = {
referer: string; referer: string
link_option: number; link_option: number
}; }
type SubscribePayloadType = { type SubscribePayloadType = {
ref_target: string; ref_target: string
referral: string; referral: string
} }
type SignatureType = { type SignatureType = {
signature: string; signature: string
}; }
class ReferralSystem { class ReferralSystem {
private apiUrl: string; private readonly apiUrl: string;
get api() { get api() {
return this.apiUrl; 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'; import fetchWithValidation from './fetchWithValidation';
// https://stackoverflow.com/a/64919133 // https://stackoverflow.com/a/64919133

View File

@@ -1,117 +1,117 @@
import BigNumber from 'bignumber.js'; import type BigNumber from 'bignumber.js';
import exchanges from './constants/exchanges'; import type exchanges from './constants/exchanges';
import subOrderStatuses from './constants/subOrderStatuses'; import type subOrderStatuses from './constants/subOrderStatuses';
import positionStatuses from './constants/positionStatuses'; import type positionStatuses from './constants/positionStatuses';
export type DeepPartial<T> = T extends object ? { export type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>; [P in keyof T]?: DeepPartial<T[P]>;
} : T; } : T;
export type AssetPairUpdate = { export type AssetPairUpdate = {
minQty: number, minQty: number
pricePrecision: number, pricePrecision: number
} }
export type SubOrder = { export type SubOrder = {
pair: string, pair: string
exchange: string, exchange: string
id: number, id: number
amount: number, amount: number
settledAmount: number, settledAmount: number
price: number, price: number
status: typeof subOrderStatuses[number], status: typeof subOrderStatuses[number]
side: 'BUY' | 'SELL', side: 'BUY' | 'SELL'
subOrdQty: number subOrdQty: number
} }
export type Balance = { export type Balance = {
tradable: string, tradable: string
reserved: string, reserved: string
contract: string, contract: string
wallet: string, wallet: string
allowance: string, allowance: string
} }
export type PositionStatus = typeof positionStatuses[number]; export type PositionStatus = typeof positionStatuses[number];
export type CFDBalance = { export type CFDBalance = {
instrument: string, instrument: string
balance: string, balance: string
profitLoss: string, profitLoss: string
fundingRate: string, fundingRate: string
equity: string, equity: string
position: string, position: string
currentPrice: string, currentPrice: string
positionPrice: string, positionPrice: string
reserves: string, reserves: string
margin: string, margin: string
marginUSD: string, marginUSD: string
freeMarginUSD: string, freeMarginUSD: string
availableWithdrawBalance: string, availableWithdrawBalance: string
leverage: string, leverage: string
status: PositionStatus, status: PositionStatus
} }
export interface Order { export type Order = {
senderAddress: string; // address senderAddress: string // address
matcherAddress: string; // address matcherAddress: string // address
baseAsset: string; // address baseAsset: string // address
quoteAsset: string; // address quoteAsset: string // address
matcherFeeAsset: string; // address matcherFeeAsset: string // address
amount: number; // uint64 amount: number // uint64
price: number; // uint64 price: number // uint64
matcherFee: number; // uint64 matcherFee: number // uint64
nonce: number; // uint64 nonce: number // uint64
expiration: number; // uint64 expiration: number // uint64
buySide: number; // uint8, 1=buy, 0=sell buySide: 0 | 1 // uint8, 1=buy, 0=sell
isPersonalSign: boolean; // bool isPersonalSign: boolean // bool
} }
export interface CFDOrder { export type CFDOrder = {
senderAddress: string; // address senderAddress: string // address
matcherAddress: string; // address matcherAddress: string // address
instrumentAddress: string; // address instrumentAddress: string // address
amount: number; // uint64 amount: number // uint64
price: number; // uint64 price: number // uint64
matcherFee: number; // uint64 matcherFee: number // uint64
nonce: number; // uint64 nonce: number // uint64
expiration: number; // uint64 expiration: number // uint64
buySide: number; // uint8, 1=buy, 0=sell buySide: 0 | 1 // uint8, 1=buy, 0=sell
isPersonalSign: boolean; // bool isPersonalSign: boolean // bool
} }
export interface SignedCFDOrder extends CFDOrder { export type SignedCFDOrder = {
id: string; // hash of Order (it's not part of order structure in smart-contract) id: string // hash of Order (it's not part of order structure in smart-contract)
signature: string; // bytes 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 { export type SignedCancelOrderRequest = {
id: string; // hash of Order (it's not part of order structure in smart-contract) id: number | string
signature: string; // bytes senderAddress: string
needWithdraw?: boolean; // bool (not supported yet by smart-contract) signature: string
} } & CancelOrderRequest
export interface CancelOrderRequest { export type Pair = {
id: number | string; name: string
senderAddress: string; baseCurrency: string
isPersonalSign: boolean; quoteCurrency: string
} lastPrice: string
openPrice: string
export interface SignedCancelOrderRequest extends CancelOrderRequest { change24h: string
id: number | string; high: string
senderAddress: string; low: string
signature: string; vol24h: string
}
export interface Pair {
name: string;
baseCurrency: string;
quoteCurrency: string;
lastPrice: string;
openPrice: string;
change24h: string;
high: string;
low: string;
vol24h: string;
} }
export enum SupportedChainId { export enum SupportedChainId {
@@ -135,114 +135,114 @@ const balanceTypes = ['exchange', 'wallet'] as const;
export type Source = typeof balanceTypes[number]; export type Source = typeof balanceTypes[number];
export type Asset = { export type Asset = {
name: string; name: string
address: string; address: string
} }
export type BalanceRequirement = { export type BalanceRequirement = {
readonly reason: string, readonly reason: string
readonly asset: Asset, readonly asset: Asset
readonly amount: string, readonly amount: string
readonly sources: Source[], readonly sources: Source[]
readonly spenderAddress?: string; readonly spenderAddress?: string
} }
export type AggregatedBalanceRequirement = { export type AggregatedBalanceRequirement = {
readonly asset: Asset, readonly asset: Asset
readonly sources: Source[], readonly sources: Source[]
readonly spenderAddress?: string; readonly spenderAddress?: string
items: Partial<Record<string, string>>, items: Partial<Record<string, string>>
} }
export type ApproveFix = { export type ApproveFix = {
readonly type: 'byApprove', readonly type: 'byApprove'
readonly targetAmount: BigNumber.Value, readonly targetAmount: BigNumber.Value
readonly spenderAddress: string readonly spenderAddress: string
} }
export type DepositFix = { export type DepositFix = {
readonly type: 'byDeposit', readonly type: 'byDeposit'
readonly amount: BigNumber.Value, readonly amount: BigNumber.Value
readonly asset: string readonly asset: string
} }
type Fix = ApproveFix | DepositFix; type Fix = ApproveFix | DepositFix;
export type BalanceIssue = { export type BalanceIssue = {
readonly asset: Asset, readonly asset: Asset
readonly message: string; readonly message: string
readonly sources: Source[], readonly sources: Source[]
readonly fixes?: Fix[], readonly fixes?: Fix[]
} }
export type Exchange = typeof exchanges[number]; export type Exchange = typeof exchanges[number];
export type OrderbookItem = { export type OrderbookItem = {
price: string, price: string
amount: string, amount: string
exchanges: Exchange[], exchanges: Exchange[]
vob: { vob: Array<{
side: 'BUY' | 'SELL', side: 'BUY' | 'SELL'
pairName: string pairName: string
}[] }>
} }
export type SwapInfoAlternative = { export type SwapInfoAlternative = {
exchanges: Exchange[], exchanges: Exchange[]
path: string[], path: string[]
marketAmountOut?: number, marketAmountOut?: number
marketAmountIn?: number, marketAmountIn?: number
marketPrice: number, marketPrice: number
availableAmountIn?: number, availableAmountIn?: number
availableAmountOut?: number, availableAmountOut?: number
} }
export type SwapInfoBase = { export type SwapInfoBase = {
swapRequestId: string, swapRequestId: string
assetIn: string, assetIn: string
assetOut: string, assetOut: string
amountIn: number, amountIn: number
amountOut: number, amountOut: number
minAmountIn: number, minAmountIn: number
minAmountOut: number, minAmountOut: number
path: string[], path: string[]
exchanges?: Exchange[], exchanges?: Exchange[]
poolOptimal: boolean, poolOptimal: boolean
price?: number, price?: number
marketPrice?: number, marketPrice?: number
orderInfo?: { orderInfo?: {
pair: string, pair: string
side: 'BUY' | 'SELL', side: 'BUY' | 'SELL'
amount: number, amount: number
safePrice: number, safePrice: number
}, }
alternatives: SwapInfoAlternative[], alternatives: SwapInfoAlternative[]
} }
export type SwapInfoByAmountIn = SwapInfoBase & { export type SwapInfoByAmountIn = SwapInfoBase & {
kind: 'exactSpend', kind: 'exactSpend'
availableAmountIn?: number, availableAmountIn?: number
marketAmountOut?: number, marketAmountOut?: number
} }
export type SwapInfoByAmountOut = SwapInfoBase & { export type SwapInfoByAmountOut = SwapInfoBase & {
kind: 'exactReceive', kind: 'exactReceive'
marketAmountIn?: number, marketAmountIn?: number
availableAmountOut?: number, availableAmountOut?: number
} }
export type SwapInfo = SwapInfoByAmountIn | SwapInfoByAmountOut; export type SwapInfo = SwapInfoByAmountIn | SwapInfoByAmountOut;
export type FuturesTradeInfo = { export type FuturesTradeInfo = {
futuresTradeRequestId: string, futuresTradeRequestId: string
sender: string, sender: string
instrument: string, instrument: string
buyPrice: number, buyPrice: number
sellPrice: number, sellPrice: number
buyPower: number, buyPower: number
sellPower: number, sellPower: number
minAmount: number, minAmount: number
} }
export enum HistoryTransactionStatus { export enum HistoryTransactionStatus {
@@ -255,30 +255,30 @@ export enum HistoryTransactionStatus {
export type VerboseOrionUnitConfig = { export type VerboseOrionUnitConfig = {
// env?: string; // env?: string;
// api: string; // api: string;
chainId: SupportedChainId; chainId: SupportedChainId
nodeJsonRpc: string; nodeJsonRpc: string
services: { services: {
orionBlockchain: { orionBlockchain: {
http: string; http: string
// For example: // For example:
// http://localhost:3001/, // http://localhost:3001/,
// http://10.123.34.23:3001/, // http://10.123.34.23:3001/,
// https://blockchain.orionprotocol.io/ // https://blockchain.orionprotocol.io/
}, }
orionAggregator: { orionAggregator: {
http: string; http: string
ws: string; ws: string
// For example: // For example:
// http://localhost:3002/, // http://localhost:3002/,
// http://10.34.23.5:3002/, // http://10.34.23.5:3002/,
// shttps://aggregator.orionprotocol.io/ // shttps://aggregator.orionprotocol.io/
}, }
priceFeed: { priceFeed: {
api: string; api: string
// For example: // For example:
// http://localhost:3003/, // http://localhost:3003/,
// http://10.23.5.11:3003/, // http://10.23.5.11:3003/,
// https://price-feed.orionprotocol.io/ // https://price-feed.orionprotocol.io/
},
} }
}; }
}

View File

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

View File

@@ -1,5 +1,5 @@
import BigNumber from 'bignumber.js'; 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. * 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) { export default function denormalizeNumber(input: ethers.BigNumber, decimals: BigNumber.Value) {
const decimalsBN = new BigNumber(decimals); 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)); return new BigNumber(input.toString()).div(new BigNumber(10).pow(decimalsBN));
} }

View File

@@ -1,5 +1,5 @@
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Source } from '../types'; import { type Source } from '../types';
export default function getAvailableFundsSources( export default function getAvailableFundsSources(
expenseType: 'amount' | 'network_fee' | 'orion_fee', 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 { ethers } from 'ethers';
import { utils } from '..';
import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION } from '../constants'; 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( export default async function getBalance(
orionAggregator: OrionAggregator, orionAggregator: OrionAggregator,
@@ -25,13 +25,13 @@ export default async function getBalance(
const assetDecimals = await assetContract.decimals(); const assetDecimals = await assetContract.decimals();
assetWalletBalance = await assetContract.balanceOf(walletAddress); assetWalletBalance = await assetContract.balanceOf(walletAddress);
denormalizedAssetInWalletBalance = utils.denormalizeNumber(assetWalletBalance, assetDecimals); denormalizedAssetInWalletBalance = denormalizeNumber(assetWalletBalance, assetDecimals);
} else { } else {
assetWalletBalance = await provider.getBalance(walletAddress); 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 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); const denormalizedAssetLockedBalanceResult = await orionAggregator.getLockedBalance(walletAddress, asset);
if (denormalizedAssetLockedBalanceResult.isErr()) { if (denormalizedAssetLockedBalanceResult.isErr()) {
throw new Error(denormalizedAssetLockedBalanceResult.error.message); throw new Error(denormalizedAssetLockedBalanceResult.error.message);

View File

@@ -1,7 +1,7 @@
import { Exchange } from '@orionprotocol/contracts'; import { type Exchange } from '@orionprotocol/contracts';
import BigNumber from 'bignumber.js'; import type BigNumber from 'bignumber.js';
import { ethers } from 'ethers'; import { type ethers } from 'ethers';
import { OrionAggregator } from '../services/OrionAggregator'; import { type OrionAggregator } from '../services/OrionAggregator';
import getBalance from './getBalance'; import getBalance from './getBalance';
export default async ( export default async (
@@ -14,7 +14,7 @@ export default async (
const balances = await Promise.all( const balances = await Promise.all(
Object.entries(balancesRequired) Object.entries(balancesRequired)
.map(async ([asset, assetAddress]) => { .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( const balance = await getBalance(
orionAggregator, orionAggregator,
asset, asset,
@@ -31,8 +31,8 @@ export default async (
); );
return balances.reduce<Partial<Record<string, { return balances.reduce<Partial<Record<string, {
exchange: BigNumber, exchange: BigNumber
wallet: BigNumber, wallet: BigNumber
}>>>((prev, curr) => ({ }>>>((prev, curr) => ({
...prev, ...prev,
[curr.asset]: curr.amount, [curr.asset]: curr.amount,

View File

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

View File

@@ -8,7 +8,7 @@ export default class HttpError extends Error {
public type: string; public type: string;
constructor(code: number, message: string | null, type: string, statusText: string) { constructor(code: number, message: string | null, type: string, statusText: string) {
super(message || ''); super(message ?? '');
this.errorMessage = message; this.errorMessage = message;
this.type = type; this.type = type;
this.statusText = statusText; this.statusText = statusText;

View File

@@ -12,6 +12,7 @@ export { default as parseExchangeTradeTransaction } from './parseExchangeTradeTr
export { default as toUpperCase } from './toUpperCase'; export { default as toUpperCase } from './toUpperCase';
export { default as toLowerCase } from './toLowerCase'; export { default as toLowerCase } from './toLowerCase';
export { default as isUppercasedNetworkCode } from './isUppercasedNetworkCode'; export { default as isUppercasedNetworkCode } from './isUppercasedNetworkCode';
export { default as getNativeCryptocurrency } from './getNativeCryptocurrency';
// export { default as HttpError } from './httpError'; // 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 envInfo = envs[env];
const envNetworks = envInfo?.networks; 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) return Object.values(chains)
.some((chain) => chain.code.toLowerCase() === networkCode.toLowerCase() && .some((chain) => chain.code.toLowerCase() === networkCode.toLowerCase() &&

View File

@@ -14,7 +14,7 @@ export default function normalizeNumber(
roundingMode: BigNumber.RoundingMode, roundingMode: BigNumber.RoundingMode,
) { ) {
const decimalsBN = new BigNumber(decimals); 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); const inputBN = new BigNumber(input);
return ethers.BigNumber.from( return ethers.BigNumber.from(
inputBN inputBN

View File

@@ -14,4 +14,4 @@ const untypedItems = Object.keys(items); // => Array<string>
@category Type guard @category Type guard
*/ */
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions // 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 = { type WithReason = {
reason: string; reason: string
} }
type WithCodeError = Error & { type WithCodeError = Error & {
code: number | string; code: number | string
} }
type WithMessage = { type WithMessage = {
message: string; message: string
} }
type WithDataError = Error & { type WithDataError = Error & {
data: Record<string, unknown>; data: Record<string, unknown>
} }
type WithError = { type WithError = {
error: Record<string | number | symbol, unknown>; error: Record<string | number | symbol, unknown>
} }
export const makePartial = <Key extends string | number | symbol, Value>(value: Record<Key, Value>): Partial<Record<Key, Value>> => value; export const makePartial = <Key extends string | number | symbol, Value>(value: Record<Key, Value>): Partial<Record<Key, Value>> => value;