mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-03-14 06:02:36 +03:00
Orion, Orion Unit, Configuration (#40)
* Refactoring * Better docs * Bump * ESLint standard * Fix * Bumo * VerboseOrionUnitConfig to types * Docs improvements * Docs improvements. Orion default env
This commit is contained in:
@@ -6,7 +6,7 @@ module.exports = {
|
|||||||
node: true,
|
node: true,
|
||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
'airbnb-base',
|
'standard',
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:@typescript-eslint/eslint-recommended',
|
'plugin:@typescript-eslint/eslint-recommended',
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
@@ -26,6 +26,10 @@ module.exports = {
|
|||||||
'@typescript-eslint',
|
'@typescript-eslint',
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
|
"comma-dangle": 0,
|
||||||
|
"semi": 0,
|
||||||
|
"space-before-function-paren": 0,
|
||||||
|
"@typescript-eslint/explicit-function-return-type": 0,
|
||||||
"no-param-reassign": [
|
"no-param-reassign": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
@@ -55,6 +59,9 @@ module.exports = {
|
|||||||
1,
|
1,
|
||||||
140,
|
140,
|
||||||
2,
|
2,
|
||||||
|
{
|
||||||
|
ignoreComments: true,
|
||||||
|
}
|
||||||
],
|
],
|
||||||
'import/extensions': [
|
'import/extensions': [
|
||||||
'error',
|
'error',
|
||||||
|
|||||||
58
ADVANCED.md
Normal file
58
ADVANCED.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Orion Verbose configuration
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const orion = new Orion({
|
||||||
|
analyticsAPI: "https://analytics-api.orionprotocol.io",
|
||||||
|
referralAPI: "https://referral-api.orionprotocol.io",
|
||||||
|
networks: {
|
||||||
|
1: {
|
||||||
|
chainId: SupportedChainId.MAINNET,
|
||||||
|
nodeJsonRpc: "https://cloudflare-eth.com/",
|
||||||
|
services: {
|
||||||
|
orionBlockchain: {
|
||||||
|
http: "http://localhost:3000",
|
||||||
|
},
|
||||||
|
orionAggregator: {
|
||||||
|
http: "http://localhost:3001/backend",
|
||||||
|
ws: "http://localhost:3001/v1",
|
||||||
|
},
|
||||||
|
priceFeed: {
|
||||||
|
api: "http://localhost:3002/price-feed",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also you can set some config as default and override it for some params
|
||||||
|
const orion = new Orion("testing", {
|
||||||
|
analyticsAPI: "https://asdasd.orionprotocol.io",
|
||||||
|
networks: {
|
||||||
|
[SupportedChainId.BSC_TESTNET]: {
|
||||||
|
nodeJsonRpc: "https://data-seed-prebsc-1-s1.binance.org:8545/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Orion unit init
|
||||||
|
const orionUnit = orion.getUnit("bsc");
|
||||||
|
// OR
|
||||||
|
const orionUnit = orion.getUnit(SupportedChainId.BSC);
|
||||||
|
// OR
|
||||||
|
const orionUnit = new OrionUnit({
|
||||||
|
chainId: SupportedChainId.BSC,
|
||||||
|
nodeJsonRpc: "https://bsc-dataseed.binance.org/",
|
||||||
|
services: {
|
||||||
|
orionBlockchain: {
|
||||||
|
http: "https://orion-bsc-api.orionprotocol.io",
|
||||||
|
},
|
||||||
|
orionAggregator: {
|
||||||
|
http: "https://orion-bsc-api.orionprotocol.io/backend",
|
||||||
|
ws: "https://orion-bsc-api.orionprotocol.io/v1",
|
||||||
|
},
|
||||||
|
priceFeed: {
|
||||||
|
api: "https://orion-bsc-api.orionprotocol.io/price-feed",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
@@ -54,10 +54,11 @@ npm i @orionprotocol/sdk
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
// Node.js
|
// Node.js
|
||||||
import { OrionUnit } from "@orionprotocol/sdk";
|
import { OrionUnit, Orion } from "@orionprotocol/sdk";
|
||||||
import { Wallet } from "ethers";
|
import { Wallet } from "ethers";
|
||||||
|
|
||||||
const orionUnit = new OrionUnit("bsc", "production"); // eth, bsc, ftm, polygon, okc available
|
const orion = new Orion();
|
||||||
|
const orionUnit = orion.getUnit("bsc"); // eth, bsc, ftm, polygon, okc available
|
||||||
const wallet = new Wallet("0x...", orionUnit.provider);
|
const wallet = new Wallet("0x...", orionUnit.provider);
|
||||||
// OrionUnit is chain-in-environment abstraction
|
// OrionUnit is chain-in-environment abstraction
|
||||||
```
|
```
|
||||||
@@ -73,7 +74,8 @@ const startApp = async (provider: BaseProvider) => {
|
|||||||
const web3Provider = new providers.Web3Provider(provider);
|
const web3Provider = new providers.Web3Provider(provider);
|
||||||
await web3Provider.ready;
|
await web3Provider.ready;
|
||||||
const signer = web3Provider.getSigner(); // ready to go
|
const signer = web3Provider.getSigner(); // ready to go
|
||||||
const orionUnit = new OrionUnit("eth", "production"); // ready to go
|
const orion = new Orion();
|
||||||
|
const orionUnit = orion.getUnit("eth"); // ready to go
|
||||||
};
|
};
|
||||||
|
|
||||||
detectEthereumProvider().then((provider) => {
|
detectEthereumProvider().then((provider) => {
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ Let's consider integration of Orion Protocol with your UI.
|
|||||||
Orion Protocol's SDK operates with OrionUnit — chain-in-environment abstraction. "Ethereum-in-production", "bsc-in-production", "fantom-in-testing", etc.
|
Orion Protocol's SDK operates with OrionUnit — chain-in-environment abstraction. "Ethereum-in-production", "bsc-in-production", "fantom-in-testing", etc.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { OrionUnit } from "@orionprotocol/sdk";
|
import { Orion } from "@orionprotocol/sdk";
|
||||||
const orionUnit = new OrionUnit("bsc", "production"); // eth, bsc, ftm available
|
const orion = new Orion();
|
||||||
|
const bscOrionUnit = orion.getUnit("bsc"); // eth, bsc, ftm, polygon, okc available
|
||||||
|
const ethOrionUnit = orion.getUnit("eth");
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2. Signer accessing
|
## 2. Signer accessing
|
||||||
|
|||||||
12
jest.config.ts
Normal file
12
jest.config.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import type { JestConfigWithTsJest } from 'ts-jest';
|
||||||
|
|
||||||
|
const config: JestConfigWithTsJest = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/__tests__/**/*.test.ts'],
|
||||||
|
modulePathIgnorePatterns: ['lib', 'node_modules'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts$': 'ts-jest',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
5750
package-lock.json
generated
5750
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
63
package.json
63
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@orionprotocol/sdk",
|
"name": "@orionprotocol/sdk",
|
||||||
"version": "0.16.8",
|
"version": "0.17.0-rc.8",
|
||||||
"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",
|
||||||
@@ -14,12 +14,14 @@
|
|||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"prebuild": "tsc",
|
"prebuild": "tsc",
|
||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
"test": "exit 0",
|
|
||||||
"coverage": "jest --coverage",
|
"coverage": "jest --coverage",
|
||||||
"lint:eslint": "eslint ./src --ext .ts,.js,.tsx,.jsx",
|
"lint:eslint": "eslint ./src --ext .ts,.js,.tsx,.jsx",
|
||||||
"lint:eslint:fix": "eslint ./src --ext .ts,.js,.tsx,.jsx --fix",
|
"lint:eslint:fix": "eslint ./src --ext .ts,.js,.tsx,.jsx --fix",
|
||||||
"postpublish": "npm run publish-npm",
|
"postpublish": "npm run publish-npm",
|
||||||
"publish-npm": "npm publish --access public --ignore-scripts --@orionprotocol:registry='https://registry.npmjs.org'"
|
"publish-npm": "npm publish --access public --ignore-scripts --@orionprotocol:registry='https://registry.npmjs.org'",
|
||||||
|
"test": "jest",
|
||||||
|
"test:coverage": "jest --coverage",
|
||||||
|
"test:watch": "jest --watch"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -37,43 +39,56 @@
|
|||||||
"url": "https://github.com/orionprotocol/sdk/issues"
|
"url": "https://github.com/orionprotocol/sdk/issues"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.11.9",
|
"@tsconfig/strictest": "^1.0.2",
|
||||||
|
"@types/express": "^4.17.17",
|
||||||
|
"@types/jest": "^29.4.0",
|
||||||
|
"@types/node": "^18.13.0",
|
||||||
|
"@types/node-fetch": "^2.6.2",
|
||||||
"@types/socket.io-client": "1.4.33",
|
"@types/socket.io-client": "1.4.33",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^9.0.0",
|
||||||
"@types/ws": "^8.5.3",
|
"@types/ws": "^8.5.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
"@typescript-eslint/eslint-plugin": "^5.51.0",
|
||||||
"@typescript-eslint/parser": "^5.16.0",
|
"@typescript-eslint/parser": "^5.51.0",
|
||||||
"babel-core": "^6.26.3",
|
"babel-core": "^6.26.3",
|
||||||
"babel-loader": "^8.2.5",
|
"babel-loader": "^8.2.5",
|
||||||
"concurrently": "^7.0.0",
|
"concurrently": "^7.0.0",
|
||||||
"eslint": "^8.12.0",
|
"eslint": "^8.33.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-plugin-import": "^2.25.4",
|
"eslint-config-standard": "^17.0.0",
|
||||||
|
"eslint-config-standard-with-typescript": "^34.0.0",
|
||||||
|
"eslint-plugin-import": "^2.27.5",
|
||||||
|
"eslint-plugin-n": "^15.6.1",
|
||||||
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"jest": "^27.5.1",
|
"jest": "^29.4.2",
|
||||||
"ts-loader": "^9.3.0",
|
"ts-jest": "^29.0.5",
|
||||||
"typescript": "^4.9.3",
|
"ts-loader": "^9.4.2",
|
||||||
"webpack": "^5.72.0",
|
"typescript": "^4.9.5",
|
||||||
"webpack-cli": "^4.9.2"
|
"webpack": "^5.75.0",
|
||||||
|
"webpack-cli": "^5.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersproject/abstract-signer": "^5.6.0",
|
"@ethersproject/abstract-signer": "^5.7.0",
|
||||||
"@ethersproject/providers": "^5.6.2",
|
"@ethersproject/providers": "^5.7.2",
|
||||||
"@lukeed/csprng": "^1.0.1",
|
"@lukeed/csprng": "^1.0.1",
|
||||||
"@orionprotocol/contracts": "0.0.10",
|
"@orionprotocol/contracts": "0.2.2",
|
||||||
"bignumber.js": "^9.0.2",
|
"bignumber.js": "^9.1.1",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"ethers": "^5.6.2",
|
"ethers": "^5.6.2",
|
||||||
|
"express": "^4.18.2",
|
||||||
"isomorphic-unfetch": "^3.1.0",
|
"isomorphic-unfetch": "^3.1.0",
|
||||||
"isomorphic-ws": "^5.0.0",
|
"isomorphic-ws": "^5.0.0",
|
||||||
"just-clone": "^5.0.1",
|
"just-clone": "^6.2.0",
|
||||||
|
"merge-anything": "^5.1.4",
|
||||||
"neverthrow": "^4.3.1",
|
"neverthrow": "^4.3.1",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"tiny-invariant": "^1.2.0",
|
"tiny-invariant": "^1.3.1",
|
||||||
"uuid": "^8.3.2",
|
"ts-is-present": "^1.2.2",
|
||||||
"ws": "^8.5.0",
|
"ts-node": "^10.9.1",
|
||||||
"zod": "^3.17.3"
|
"uuid": "^9.0.0",
|
||||||
|
"ws": "^8.12.0",
|
||||||
|
"zod": "^3.20.2"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/orionprotocol/sdk#readme",
|
"homepage": "https://github.com/orionprotocol/sdk#readme",
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import clone from 'just-clone';
|
|||||||
import { ERC20__factory } from '@orionprotocol/contracts';
|
import { ERC20__factory } from '@orionprotocol/contracts';
|
||||||
import { utils } from '.';
|
import { utils } from '.';
|
||||||
import { APPROVE_ERC20_GAS_LIMIT, NATIVE_CURRENCY_PRECISION } from './constants';
|
import { APPROVE_ERC20_GAS_LIMIT, NATIVE_CURRENCY_PRECISION } from './constants';
|
||||||
import {
|
import type {
|
||||||
AggregatedBalanceRequirement, ApproveFix, Asset, BalanceIssue, BalanceRequirement, Source,
|
AggregatedBalanceRequirement, ApproveFix, Asset, BalanceIssue, BalanceRequirement, Source,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { denormalizeNumber } from './utils';
|
import { denormalizeNumber } from './utils';
|
||||||
@@ -82,9 +82,9 @@ export default class BalanceGuard {
|
|||||||
return requirements
|
return requirements
|
||||||
.reduce<AggregatedBalanceRequirement[]>((prev, curr) => {
|
.reduce<AggregatedBalanceRequirement[]>((prev, curr) => {
|
||||||
const aggregatedBalanceRequirement = prev.find(
|
const aggregatedBalanceRequirement = prev.find(
|
||||||
(item) => item.asset.address === curr.asset.address
|
(item) => item.asset.address === curr.asset.address &&
|
||||||
&& arrayEquals(item.sources, curr.sources)
|
arrayEquals(item.sources, curr.sources) &&
|
||||||
&& item.spenderAddress === curr.spenderAddress,
|
item.spenderAddress === curr.spenderAddress,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (aggregatedBalanceRequirement) {
|
if (aggregatedBalanceRequirement) {
|
||||||
@@ -163,9 +163,9 @@ export default class BalanceGuard {
|
|||||||
|
|
||||||
async check(fixAutofixable?: boolean) {
|
async check(fixAutofixable?: boolean) {
|
||||||
this.logger?.(`Balance requirements: ${this.requirements
|
this.logger?.(`Balance requirements: ${this.requirements
|
||||||
.map((requirement) => `${requirement.amount} ${requirement.asset.name} `
|
.map((requirement) => `${requirement.amount} ${requirement.asset.name} ` +
|
||||||
+ `for '${requirement.reason}' `
|
`for '${requirement.reason}' ` +
|
||||||
+ `from [${requirement.sources.join(' + ')}]`)
|
`from [${requirement.sources.join(' + ')}]`)
|
||||||
.join(', ')}`);
|
.join(', ')}`);
|
||||||
|
|
||||||
const remainingBalances = clone(this.balances);
|
const remainingBalances = clone(this.balances);
|
||||||
@@ -206,9 +206,9 @@ export default class BalanceGuard {
|
|||||||
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?.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`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -260,10 +260,10 @@ export default class BalanceGuard {
|
|||||||
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?.toString()} `
|
`Needed: ${itemsAmountSum.toString()}, available: ${(available ?? '[UNDEFINED]')?.toString()} ` +
|
||||||
+ `(exchange: ${exchangeBalance?.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) {
|
||||||
@@ -290,11 +290,13 @@ export default class BalanceGuard {
|
|||||||
asset,
|
asset,
|
||||||
sources: ['exchange', 'wallet'],
|
sources: ['exchange', 'wallet'],
|
||||||
fixes: [
|
fixes: [
|
||||||
...resetRequired ? [{
|
...resetRequired
|
||||||
type: 'byApprove' as const,
|
? [{
|
||||||
targetAmount: 0,
|
type: 'byApprove' as const,
|
||||||
spenderAddress,
|
targetAmount: 0,
|
||||||
}] : [],
|
spenderAddress,
|
||||||
|
}]
|
||||||
|
: [],
|
||||||
{
|
{
|
||||||
type: 'byApprove',
|
type: 'byApprove',
|
||||||
targetAmount: targetApprove,
|
targetAmount: targetApprove,
|
||||||
@@ -351,8 +353,8 @@ 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 issueMessage = `Not enough ${asset.name} on wallet balance. `
|
const issueMessage = `Not enough ${asset.name} on wallet balance. ` +
|
||||||
+ `Needed: ${itemsAmountSum.toString()}, available (approved): ${approvedWalletBalance.toString()}. ${approveIsHelpful
|
`Needed: ${itemsAmountSum.toString()}, available (approved): ${approvedWalletBalance.toString()}. ${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) {
|
||||||
@@ -379,11 +381,13 @@ export default class BalanceGuard {
|
|||||||
asset,
|
asset,
|
||||||
sources: ['wallet'],
|
sources: ['wallet'],
|
||||||
fixes: [
|
fixes: [
|
||||||
...resetRequired ? [{
|
...resetRequired
|
||||||
type: 'byApprove' as const,
|
? [{
|
||||||
targetAmount: 0,
|
type: 'byApprove' as const,
|
||||||
spenderAddress,
|
targetAmount: 0,
|
||||||
}] : [],
|
spenderAddress,
|
||||||
|
}]
|
||||||
|
: [],
|
||||||
{
|
{
|
||||||
type: 'byApprove',
|
type: 'byApprove',
|
||||||
targetAmount: targetApprove,
|
targetAmount: targetApprove,
|
||||||
@@ -418,8 +422,8 @@ export default class BalanceGuard {
|
|||||||
balanceIssues.push({
|
balanceIssues.push({
|
||||||
asset,
|
asset,
|
||||||
sources: ['wallet'],
|
sources: ['wallet'],
|
||||||
message: `Not enough ${asset.name} on wallet balance. `
|
message: `Not enough ${asset.name} on wallet balance. ` +
|
||||||
+ `You need to deposit at least ${lackAmount.toString()} ${asset.name} into wallet contract`,
|
`You need to deposit at least ${lackAmount.toString()} ${asset.name} into wallet contract`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -428,7 +432,10 @@ export default class BalanceGuard {
|
|||||||
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) {
|
||||||
throw new Error(`Balance issues (address ${walletAddress}): ${balanceIssues.map((issue, i) => `${i + 1}. ${issue.message}`).join('\n')}`);
|
throw new Error(
|
||||||
|
`Balance issues (address ${walletAddress}): ` +
|
||||||
|
`${balanceIssues.map((issue, i) => `${i + 1}. ${issue.message}`).join('\n')}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
143
src/Orion/index.ts
Normal file
143
src/Orion/index.ts
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
import { merge } from 'merge-anything';
|
||||||
|
import { chains, envs } from '../config';
|
||||||
|
import OrionUnit from '../OrionUnit';
|
||||||
|
import OrionAnalytics from '../services/OrionAnalytics';
|
||||||
|
import { ReferralSystem } from '../services/ReferralSystem';
|
||||||
|
import { DeepPartial, SupportedChainId, VerboseOrionUnitConfig } from '../types';
|
||||||
|
import { isValidChainId } from '../utils';
|
||||||
|
|
||||||
|
type EnvConfig = {
|
||||||
|
analyticsAPI: string;
|
||||||
|
referralAPI: string;
|
||||||
|
networks: Partial<
|
||||||
|
Record<
|
||||||
|
SupportedChainId,
|
||||||
|
VerboseOrionUnitConfig
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// type KnownEnv = 'testing' | 'staging' | 'production';
|
||||||
|
|
||||||
|
export default class Orion {
|
||||||
|
public readonly env?: string;
|
||||||
|
|
||||||
|
public readonly units: Partial<Record<SupportedChainId, OrionUnit>>;
|
||||||
|
|
||||||
|
public readonly orionAnalytics: OrionAnalytics;
|
||||||
|
|
||||||
|
public readonly referralSystem: ReferralSystem;
|
||||||
|
|
||||||
|
constructor();
|
||||||
|
constructor(
|
||||||
|
env: string,
|
||||||
|
overrides?: DeepPartial<EnvConfig>
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor(config: EnvConfig);
|
||||||
|
|
||||||
|
// TODO: get tradable assets (aggregated)
|
||||||
|
|
||||||
|
// TODO: get tradable pairs (aggregated)
|
||||||
|
|
||||||
|
// TODO: bridge
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
envOrConfig: string | EnvConfig = 'production',
|
||||||
|
overrides?: DeepPartial<EnvConfig>
|
||||||
|
) {
|
||||||
|
let config: EnvConfig;
|
||||||
|
if (typeof envOrConfig === 'string') {
|
||||||
|
const envConfig = envs[envOrConfig];
|
||||||
|
if (!envConfig) throw new Error(`Invalid environment: ${envOrConfig}. Available environments: ${Object.keys(envs).join(', ')}`);
|
||||||
|
this.env = envOrConfig;
|
||||||
|
config = {
|
||||||
|
analyticsAPI: envConfig.analyticsAPI,
|
||||||
|
referralAPI: envConfig.referralAPI,
|
||||||
|
networks: Object.entries(envConfig.networks).map(([chainId, networkConfig]) => {
|
||||||
|
if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`);
|
||||||
|
const chainConfig = chains[chainId];
|
||||||
|
if (!chainConfig) throw new Error(`Chain config not found: ${chainId}. Available chains: ${Object.keys(chains).join(', ')}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
env: envOrConfig,
|
||||||
|
chainId,
|
||||||
|
api: networkConfig.api,
|
||||||
|
nodeJsonRpc: chainConfig.rpc,
|
||||||
|
services: {
|
||||||
|
orionBlockchain: {
|
||||||
|
http: networkConfig.api + networkConfig.services.blockchain.http,
|
||||||
|
},
|
||||||
|
orionAggregator: {
|
||||||
|
http: networkConfig.api + networkConfig.services.aggregator.http,
|
||||||
|
ws: networkConfig.api + networkConfig.services.aggregator.ws,
|
||||||
|
},
|
||||||
|
priceFeed: {
|
||||||
|
api: networkConfig.api + networkConfig.services.priceFeed.all,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.reduce<Partial<Record<SupportedChainId, VerboseOrionUnitConfig>>>((acc, cur) => {
|
||||||
|
acc[cur.chainId] = cur;
|
||||||
|
return acc;
|
||||||
|
}, {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (overrides) {
|
||||||
|
config = merge(config, overrides);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config = envOrConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.orionAnalytics = new OrionAnalytics(config.analyticsAPI);
|
||||||
|
this.referralSystem = new ReferralSystem(config.referralAPI);
|
||||||
|
|
||||||
|
this.units = Object.entries(config.networks)
|
||||||
|
.reduce<Partial<Record<SupportedChainId, OrionUnit>>>((acc, [chainId, networkConfig]) => {
|
||||||
|
if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`);
|
||||||
|
const chainConfig = chains[chainId];
|
||||||
|
if (!chainConfig) throw new Error(`Invalid chainId: ${chainId}`);
|
||||||
|
|
||||||
|
const orionUnit = new OrionUnit({
|
||||||
|
// env: networkConfig.env,
|
||||||
|
chainId,
|
||||||
|
// api: networkConfig.api,
|
||||||
|
nodeJsonRpc: networkConfig.nodeJsonRpc,
|
||||||
|
services: networkConfig.services,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[chainId]: orionUnit,
|
||||||
|
}
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
get unitsArray() {
|
||||||
|
return Object.entries(this.units).map(([, unit]) => unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUnit(chainId: SupportedChainId): OrionUnit;
|
||||||
|
|
||||||
|
getUnit(networkCode: string): OrionUnit;
|
||||||
|
|
||||||
|
getUnit(networkCodeOrChainId: string): OrionUnit {
|
||||||
|
let unit: OrionUnit | undefined;
|
||||||
|
if (isValidChainId(networkCodeOrChainId)) {
|
||||||
|
unit = this.units[networkCodeOrChainId];
|
||||||
|
} else {
|
||||||
|
unit = this.unitsArray.find((u) => u.networkCode === networkCodeOrChainId);
|
||||||
|
}
|
||||||
|
if (!unit) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid network code: ${networkCodeOrChainId}. ` +
|
||||||
|
`Available network codes: ${this.unitsArray.map((u) => u.networkCode).join(', ')}`);
|
||||||
|
}
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSiblingsOf(chainId: SupportedChainId) {
|
||||||
|
return this.unitsArray.filter((unit) => unit.chainId !== chainId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,11 +85,11 @@ export default async function getSwapInfo({
|
|||||||
if (options?.poolOnly) {
|
if (options?.poolOnly) {
|
||||||
route = 'pool';
|
route = 'pool';
|
||||||
} else if (
|
} else if (
|
||||||
swapExchanges !== undefined
|
swapExchanges !== undefined &&
|
||||||
&& poolExchangesList.length > 0
|
poolExchangesList.length > 0 &&
|
||||||
&& swapExchanges.length === 1
|
swapExchanges.length === 1 &&
|
||||||
&& firstSwapExchange
|
firstSwapExchange &&
|
||||||
&& poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange)
|
poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange)
|
||||||
) {
|
) {
|
||||||
route = 'pool';
|
route = 'pool';
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -170,11 +170,11 @@ export default async function swapMarket({
|
|||||||
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
|
swapExchanges !== undefined &&
|
||||||
&& poolExchangesList.length > 0
|
poolExchangesList.length > 0 &&
|
||||||
&& swapExchanges.length === 1
|
swapExchanges.length === 1 &&
|
||||||
&& firstSwapExchange
|
firstSwapExchange &&
|
||||||
&& 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)`);
|
||||||
route = 'pool';
|
route = 'pool';
|
||||||
|
|||||||
@@ -1,34 +1,21 @@
|
|||||||
import { ethers } from 'ethers';
|
import { ethers } from 'ethers';
|
||||||
import { OrionAggregator } from '../services/OrionAggregator';
|
import { OrionAggregator } from '../services/OrionAggregator';
|
||||||
import OrionAnalytics from '../services/OrionAnalytics';
|
|
||||||
import { OrionBlockchain } from '../services/OrionBlockchain';
|
import { OrionBlockchain } from '../services/OrionBlockchain';
|
||||||
import { PriceFeed } from '../services/PriceFeed';
|
import { PriceFeed } from '../services/PriceFeed';
|
||||||
import { SupportedChainId } from '../types';
|
import type { SupportedChainId, VerboseOrionUnitConfig } from '../types';
|
||||||
import Exchange from './Exchange';
|
import Exchange from './Exchange';
|
||||||
import FarmingManager from './FarmingManager';
|
import FarmingManager from './FarmingManager';
|
||||||
import { chains, envs } from '../config';
|
import { chains } from '../config';
|
||||||
import { isValidChainId } from '../utils';
|
|
||||||
import { ReferralSystem } from '../services/ReferralSystem';
|
|
||||||
|
|
||||||
const orionAnalyticsUrl = 'https://trade.orionprotocol.io';
|
// type KnownConfig = {
|
||||||
|
// env: string;
|
||||||
|
// chainId: SupportedChainId;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type OrionUnitConfig = KnownConfig | VerboseOrionUnitConfig;
|
||||||
|
|
||||||
type Options = {
|
|
||||||
api?: string;
|
|
||||||
nodeJsonRpc?: string;
|
|
||||||
services?: {
|
|
||||||
orionBlockchain?: {
|
|
||||||
api?: string;
|
|
||||||
},
|
|
||||||
orionAggregator?: {
|
|
||||||
api?: string;
|
|
||||||
},
|
|
||||||
priceFeed?: {
|
|
||||||
api?: string;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export default class OrionUnit {
|
export default class OrionUnit {
|
||||||
public readonly env: string;
|
// public readonly env?: string;
|
||||||
|
|
||||||
public readonly networkCode: string;
|
public readonly networkCode: string;
|
||||||
|
|
||||||
@@ -42,122 +29,69 @@ export default class OrionUnit {
|
|||||||
|
|
||||||
public readonly priceFeed: PriceFeed;
|
public readonly priceFeed: PriceFeed;
|
||||||
|
|
||||||
public readonly orionAnalytics: OrionAnalytics;
|
|
||||||
|
|
||||||
public readonly exchange: Exchange;
|
public readonly exchange: Exchange;
|
||||||
|
|
||||||
public readonly farmingManager: FarmingManager;
|
public readonly farmingManager: FarmingManager;
|
||||||
|
|
||||||
public readonly apiUrl: string;
|
// constructor(config: KnownConfig);
|
||||||
|
// constructor(config: VerboseConfig);
|
||||||
public readonly referralSystem: ReferralSystem;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
chain: string,
|
|
||||||
env: string,
|
|
||||||
options?: Options,
|
|
||||||
) {
|
|
||||||
let chainId: SupportedChainId;
|
|
||||||
let customApi: string | undefined;
|
|
||||||
let customRpc: string | undefined;
|
|
||||||
let chainInfo: typeof chains[SupportedChainId] | undefined;
|
|
||||||
|
|
||||||
if (!(env in envs)) {
|
|
||||||
if (env === 'custom') {
|
|
||||||
if (!options?.api) throw new Error('Your env is custom. You should provide api url in options');
|
|
||||||
const { api } = options;
|
|
||||||
customApi = api;
|
|
||||||
if (isValidChainId(chain)) {
|
|
||||||
chainId = chain;
|
|
||||||
chainInfo = chains[chain];
|
|
||||||
} else throw new Error('Your chainId is invalid');
|
|
||||||
} else {
|
|
||||||
throw new Error(`Env '${env}' not found. Available environments is: ${Object.keys(envs).join(', ')}`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const envInfo = envs[env];
|
|
||||||
const envNetworks = envInfo?.networks;
|
|
||||||
if (envNetworks === undefined) throw new Error('Env networks is undefined (constructor)');
|
|
||||||
|
|
||||||
if (isValidChainId(chain)) chainId = chain;
|
|
||||||
else {
|
|
||||||
const targetChains = Object
|
|
||||||
.keys(chains)
|
|
||||||
.filter(isValidChainId)
|
|
||||||
.filter((ch) => {
|
|
||||||
const chInfo = chains[ch];
|
|
||||||
if (!chInfo) return false;
|
|
||||||
return (chInfo.chainId in envNetworks)
|
|
||||||
&& (chInfo.code.toLowerCase() === chain.toLowerCase());
|
|
||||||
});
|
|
||||||
if (targetChains.length !== 1) {
|
|
||||||
throw new Error(
|
|
||||||
targetChains.length > 1
|
|
||||||
? 'Ambiguation detected. '
|
|
||||||
+ `Found ${targetChains.length} chain ids [${targetChains.join(', ')}] for chain name '${chain}' in env '${env}'. Expected 1.`
|
|
||||||
: `Chains not found for chain name '${chain}' in env '${env}'.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const firstTargetChain = targetChains[0];
|
|
||||||
if (firstTargetChain === undefined) throw new Error('First target chain is undefined');
|
|
||||||
chainId = firstTargetChain;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(chainId in envNetworks)) {
|
|
||||||
throw new Error(`Chain '${chainId}' not found. `
|
|
||||||
+ `Available chains in selected environment (${env}) is: ${Object.keys(envNetworks).join(', ')}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const envNetworkInfo = envNetworks[chainId];
|
|
||||||
chainInfo = chains[chainId];
|
|
||||||
|
|
||||||
if (!envNetworkInfo) throw new Error('Env network info is required');
|
|
||||||
|
|
||||||
customApi = envNetworkInfo.api;
|
|
||||||
customRpc = envNetworkInfo.rpc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
constructor(config: VerboseOrionUnitConfig) {
|
||||||
|
const chainInfo = chains[config.chainId];
|
||||||
if (!chainInfo) throw new Error('Chain info is required');
|
if (!chainInfo) throw new Error('Chain info is required');
|
||||||
|
|
||||||
this.chainId = chainId;
|
// if ('env' in config)
|
||||||
|
// this.env = config.env;
|
||||||
|
this.chainId = config.chainId;
|
||||||
this.networkCode = chainInfo.code;
|
this.networkCode = chainInfo.code;
|
||||||
this.provider = new ethers.providers.StaticJsonRpcProvider(options?.nodeJsonRpc ?? customRpc ?? chainInfo.rpc);
|
this.provider = new ethers.providers.StaticJsonRpcProvider(config.nodeJsonRpc);
|
||||||
this.env = env;
|
|
||||||
this.apiUrl = customApi;
|
|
||||||
|
|
||||||
this.orionBlockchain = new OrionBlockchain(
|
this.orionBlockchain = new OrionBlockchain(config.services.orionBlockchain.http);
|
||||||
options?.services?.orionBlockchain?.api
|
|
||||||
?? options?.api
|
|
||||||
?? customApi,
|
|
||||||
);
|
|
||||||
|
|
||||||
const oaUrl = new URL(options?.services?.orionAggregator?.api ?? options?.api ?? customApi);
|
|
||||||
const oaWsProtocol = oaUrl.protocol === 'https:' ? 'wss' : 'ws';
|
|
||||||
const orionAggregatorWsUrl = `${oaWsProtocol}://${oaUrl.host + (oaUrl.pathname === '/' ? '' : oaUrl.pathname)}/v1`;
|
|
||||||
this.orionAggregator = new OrionAggregator(
|
this.orionAggregator = new OrionAggregator(
|
||||||
options?.services?.orionAggregator?.api ?? `${options?.api ?? customApi}/backend`,
|
config.services.orionAggregator.http,
|
||||||
orionAggregatorWsUrl,
|
config.services.orionAggregator.ws,
|
||||||
);
|
);
|
||||||
this.priceFeed = new PriceFeed(
|
this.priceFeed = new PriceFeed(config.services.priceFeed.api);
|
||||||
options?.services?.priceFeed?.api
|
|
||||||
?? `${options?.api ?? customApi}/price-feed`,
|
|
||||||
);
|
|
||||||
this.orionAnalytics = new OrionAnalytics(orionAnalyticsUrl);
|
|
||||||
this.exchange = new Exchange(this);
|
this.exchange = new Exchange(this);
|
||||||
this.farmingManager = new FarmingManager(this);
|
this.farmingManager = new FarmingManager(this);
|
||||||
this.referralSystem = new ReferralSystem(options?.api ?? customApi, env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get siblings() {
|
// get siblings() {
|
||||||
const envInfo = envs[this.env];
|
// if (!this.env) throw new Error('Sibling is not available, because env is not set');
|
||||||
const envNetworks = envInfo?.networks;
|
|
||||||
|
|
||||||
if (envNetworks === undefined) throw new Error('Env networks is undefined (siblings)');
|
// const envInfo = envs[this.env];
|
||||||
|
// const envNetworks = envInfo?.networks;
|
||||||
|
|
||||||
const siblingsNetworks = Object
|
// if (envNetworks === undefined) throw new Error('Env networks is undefined (siblings)');
|
||||||
.keys(envNetworks)
|
|
||||||
.filter(isValidChainId)
|
// const orionUnits: OrionUnit[] = [];
|
||||||
.filter((chainId) => chainId !== this.chainId);
|
// Object
|
||||||
return siblingsNetworks.map((chainId) => new OrionUnit(chainId, this.env));
|
// .entries(envNetworks)
|
||||||
}
|
// .forEach(([chainId, config]) => {
|
||||||
|
// if (!isValidChainId(chainId)) throw new Error('Invalid chainId');
|
||||||
|
// if (chainId !== this.chainId) {
|
||||||
|
// const chainConfig = chains[chainId];
|
||||||
|
// if (!chainConfig) throw new Error('Chain config is required');
|
||||||
|
// const orionUnit = new OrionUnit({
|
||||||
|
// api: config.api,
|
||||||
|
// chainId,
|
||||||
|
// nodeJsonRpc: chainConfig.rpc ?? config.rpc,
|
||||||
|
// services: {
|
||||||
|
// orionBlockchain: {
|
||||||
|
// http: config.api + config.services.blockchain.http,
|
||||||
|
// },
|
||||||
|
// orionAggregator: {
|
||||||
|
// http: config.api + config.services.aggregator.http,
|
||||||
|
// ws: config.api + config.services.aggregator.ws,
|
||||||
|
// },
|
||||||
|
// priceFeed: {
|
||||||
|
// api: config.api + config.services.priceFeed.all,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// orionUnits.push(orionUnit);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// return orionUnits;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
319
src/__tests__/basic.test.ts
Normal file
319
src/__tests__/basic.test.ts
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
// import { ethers } from 'ethers';
|
||||||
|
import Orion from '../Orion';
|
||||||
|
import OrionAnalytics from '../services/OrionAnalytics';
|
||||||
|
import { ReferralSystem } from '../services/ReferralSystem';
|
||||||
|
import simpleFetch from '../simpleFetch';
|
||||||
|
import { SupportedChainId } from '../types';
|
||||||
|
import express from 'express';
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
import http from 'http';
|
||||||
|
import httpToWS from '../utils/httpToWS';
|
||||||
|
|
||||||
|
const createServer = (externalHost: string) => {
|
||||||
|
const app = express();
|
||||||
|
const server = http.createServer(app);
|
||||||
|
const wss = new WebSocket.Server({ server });
|
||||||
|
|
||||||
|
let externalWs: WebSocket | null = null;
|
||||||
|
wss.on('connection', (ws, req) => {
|
||||||
|
const targetUrl = httpToWS(`${externalHost}${req.url}`);
|
||||||
|
externalWs = new WebSocket(targetUrl);
|
||||||
|
|
||||||
|
externalWs.on('open', () => {
|
||||||
|
ws.on('message', message => {
|
||||||
|
externalWs?.send(message);
|
||||||
|
});
|
||||||
|
|
||||||
|
externalWs?.on('message', message => {
|
||||||
|
ws.send(message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get(
|
||||||
|
'*',
|
||||||
|
async (req, res) => {
|
||||||
|
const routeFromURL = req.url;
|
||||||
|
try {
|
||||||
|
const targetUrl = `${externalHost}${routeFromURL}`;
|
||||||
|
const response = await fetch(targetUrl);
|
||||||
|
const text = await response.text();
|
||||||
|
res.send(text);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).send({
|
||||||
|
error: 'Failed to retrieve data from external resource'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(0);
|
||||||
|
const address = server.address();
|
||||||
|
|
||||||
|
if (typeof address === 'string') {
|
||||||
|
throw new Error(`Server address is a string: ${address}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
port: address?.port,
|
||||||
|
close: () => new Promise((resolve) => {
|
||||||
|
externalWs?.close();
|
||||||
|
server.close(resolve);
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Orion', () => {
|
||||||
|
test('Init Orion testing', () => {
|
||||||
|
const orion = new Orion('testing');
|
||||||
|
expect(orion.orionAnalytics).toBeInstanceOf(OrionAnalytics);
|
||||||
|
expect(orion.referralSystem).toBeInstanceOf(ReferralSystem);
|
||||||
|
expect(orion.unitsArray.length).toBe(4); // eth, bsc, polygon, fantom
|
||||||
|
|
||||||
|
const orionUnitBSC = orion.units[SupportedChainId.BSC_TESTNET];
|
||||||
|
expect(orionUnitBSC?.chainId).toBe(SupportedChainId.BSC_TESTNET);
|
||||||
|
// expect(orionUnitBSC?.env).toBe('testing');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.BSC_TESTNET)).toHaveLength(3);
|
||||||
|
expect(orionUnitBSC?.networkCode).toBe('bsc');
|
||||||
|
|
||||||
|
const orionUnitRopsten = orion.units[SupportedChainId.ROPSTEN]
|
||||||
|
expect(orionUnitRopsten?.chainId).toBe(SupportedChainId.ROPSTEN);
|
||||||
|
// expect(orionUnitRopsten?.env).toBe('testing');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.ROPSTEN)).toHaveLength(3);
|
||||||
|
expect(orionUnitRopsten?.networkCode).toBe('eth');
|
||||||
|
|
||||||
|
const orionUnitPolygon = orion.units[SupportedChainId.POLYGON_TESTNET];
|
||||||
|
expect(orionUnitPolygon?.chainId).toBe(SupportedChainId.POLYGON_TESTNET);
|
||||||
|
// expect(orionUnitPolygon?.env).toBe('testing');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.POLYGON_TESTNET)).toHaveLength(3);
|
||||||
|
expect(orionUnitPolygon?.networkCode).toBe('polygon');
|
||||||
|
|
||||||
|
const orionUnitFantom = orion.units[SupportedChainId.FANTOM_TESTNET];
|
||||||
|
expect(orionUnitFantom?.chainId).toBe(SupportedChainId.FANTOM_TESTNET);
|
||||||
|
// expect(orionUnitFantom?.env).toBe('testing');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.FANTOM_TESTNET)).toHaveLength(3);
|
||||||
|
expect(orionUnitFantom?.networkCode).toBe('ftm');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Init Orion production', () => {
|
||||||
|
const orion = new Orion();
|
||||||
|
expect(orion.env).toBe('production');
|
||||||
|
expect(orion.orionAnalytics).toBeInstanceOf(OrionAnalytics);
|
||||||
|
expect(orion.referralSystem).toBeInstanceOf(ReferralSystem);
|
||||||
|
expect(orion.unitsArray.length).toBe(5); // eth, bsc, polygon, fantom, okc
|
||||||
|
|
||||||
|
const orionUnitBSC = orion.units[SupportedChainId.BSC];
|
||||||
|
expect(orionUnitBSC?.chainId).toBe(SupportedChainId.BSC);
|
||||||
|
// expect(orionUnitBSC?.env).toBe('production');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.BSC)).toHaveLength(4);
|
||||||
|
expect(orionUnitBSC?.networkCode).toBe('bsc');
|
||||||
|
|
||||||
|
const orionUnitETH = orion.units[SupportedChainId.MAINNET]
|
||||||
|
expect(orionUnitETH?.chainId).toBe(SupportedChainId.MAINNET);
|
||||||
|
// expect(orionUnitETH?.env).toBe('production');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.MAINNET)).toHaveLength(4);
|
||||||
|
expect(orionUnitETH?.networkCode).toBe('eth');
|
||||||
|
|
||||||
|
const orionUnitPolygon = orion.units[SupportedChainId.POLYGON];
|
||||||
|
expect(orionUnitPolygon?.chainId).toBe(SupportedChainId.POLYGON);
|
||||||
|
// expect(orionUnitPolygon?.env).toBe('production');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.POLYGON)).toHaveLength(4);
|
||||||
|
expect(orionUnitPolygon?.networkCode).toBe('polygon');
|
||||||
|
|
||||||
|
const orionUnitFantom = orion.units[SupportedChainId.FANTOM_OPERA];
|
||||||
|
expect(orionUnitFantom?.chainId).toBe(SupportedChainId.FANTOM_OPERA);
|
||||||
|
// expect(orionUnitFantom?.env).toBe('production');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.FANTOM_OPERA)).toHaveLength(4);
|
||||||
|
expect(orionUnitFantom?.networkCode).toBe('ftm');
|
||||||
|
|
||||||
|
const orionUnitOKC = orion.units[SupportedChainId.OKC];
|
||||||
|
expect(orionUnitOKC?.chainId).toBe(SupportedChainId.OKC);
|
||||||
|
// expect(orionUnitOKC?.env).toBe('production');
|
||||||
|
expect(orion.getSiblingsOf(SupportedChainId.OKC)).toHaveLength(4);
|
||||||
|
expect(orionUnitOKC?.networkCode).toBe('okc');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Init Orion custom', async () => {
|
||||||
|
const server0 = createServer('https://trade.orionprotocol.io');
|
||||||
|
const server1 = createServer('https://trade.orionprotocol.io');
|
||||||
|
const server2 = createServer('https://trade.orionprotocol.io');
|
||||||
|
|
||||||
|
const orionBlockchainAPI = `http://localhost:${server0.port}`;
|
||||||
|
const orionAggregatorAPI = `http://localhost:${server1.port}`;
|
||||||
|
const orionPriceFeedAPI = `http://localhost:${server2.port}`;
|
||||||
|
|
||||||
|
const orion = new Orion({
|
||||||
|
analyticsAPI: 'https://analytics-api.orionprotocol.io',
|
||||||
|
referralAPI: 'https://referral-api.orionprotocol.io',
|
||||||
|
networks: {
|
||||||
|
1: {
|
||||||
|
// api: 'https://api.orionprotocol.io',
|
||||||
|
chainId: SupportedChainId.MAINNET,
|
||||||
|
nodeJsonRpc: 'https://cloudflare-eth.com/',
|
||||||
|
services: {
|
||||||
|
orionBlockchain: {
|
||||||
|
http: orionBlockchainAPI,
|
||||||
|
},
|
||||||
|
orionAggregator: {
|
||||||
|
http: orionAggregatorAPI + '/backend',
|
||||||
|
ws: `http://localhost:${server1.port}/v1`,
|
||||||
|
},
|
||||||
|
priceFeed: {
|
||||||
|
api: orionPriceFeedAPI + '/price-feed',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const orionUnit = orion.unitsArray[0];
|
||||||
|
if (!orionUnit) {
|
||||||
|
throw new Error('Orion unit is not defined');
|
||||||
|
}
|
||||||
|
expect(orion.orionAnalytics).toBeInstanceOf(OrionAnalytics);
|
||||||
|
expect(orion.referralSystem).toBeInstanceOf(ReferralSystem);
|
||||||
|
expect(orion.unitsArray.length).toBe(1); // eth
|
||||||
|
expect(orion.orionAnalytics.api).toBe('https://analytics-api.orionprotocol.io');
|
||||||
|
expect(orion.referralSystem.api).toBe('https://referral-api.orionprotocol.io');
|
||||||
|
expect(orionUnit.chainId).toBe(SupportedChainId.MAINNET);
|
||||||
|
// expect(orionUnit.env).toBeUndefined();
|
||||||
|
// expect(orion.units[0]?.orionAggregator.api).toBe('http://localhost:3001');
|
||||||
|
expect(orionUnit.orionAggregator.ws.api).toBe(`ws://localhost:${server1.port}/v1`);
|
||||||
|
expect(orionUnit.orionBlockchain.api).toBe(orionBlockchainAPI);
|
||||||
|
expect(orionUnit.priceFeed.api).toBe(orionPriceFeedAPI + '/price-feed');
|
||||||
|
expect(orionUnit.provider.connection.url).toBe('https://cloudflare-eth.com/');
|
||||||
|
|
||||||
|
const info = await simpleFetch(orionUnit.orionBlockchain.getInfo)();
|
||||||
|
expect(info).toBeDefined();
|
||||||
|
|
||||||
|
const spotData = await simpleFetch(orionUnit.orionAggregator.getPairConfigs)('spot');
|
||||||
|
expect(spotData).toBeDefined();
|
||||||
|
|
||||||
|
const priceData = await simpleFetch(orionUnit.priceFeed.getCandles)(
|
||||||
|
'BTC-USDT',
|
||||||
|
Math.floor((Date.now() - 1000 * 60 * 60 * 24 * 30) / 1000), // 1 month ago
|
||||||
|
Math.floor(Date.now() / 1000), // now
|
||||||
|
'1d'
|
||||||
|
);
|
||||||
|
expect(priceData).toBeDefined();
|
||||||
|
|
||||||
|
const allTickersDone = await new Promise<boolean>((resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
reject(new Error('Timeout'));
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
const { unsubscribe } = orionUnit.priceFeed.ws.subscribe(
|
||||||
|
'allTickers',
|
||||||
|
{
|
||||||
|
callback: () => {
|
||||||
|
resolve(true);
|
||||||
|
unsubscribe();
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
expect(allTickersDone).toBe(true);
|
||||||
|
|
||||||
|
await server0.close();
|
||||||
|
await server1.close();
|
||||||
|
await server2.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Init Orion testing with overrides', () => {
|
||||||
|
const orion = new Orion('testing', {
|
||||||
|
analyticsAPI: 'https://asdasd.orionprotocol.io',
|
||||||
|
referralAPI: 'https://zxczxc.orionprotocol.io',
|
||||||
|
networks: {
|
||||||
|
[SupportedChainId.BSC_TESTNET]: {
|
||||||
|
nodeJsonRpc: 'https://data-seed-prebsc-1-s1.binance.org:8545/',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const bscOrionUnit = orion.units[SupportedChainId.BSC_TESTNET]
|
||||||
|
expect(bscOrionUnit?.provider.connection.url).toBe('https://data-seed-prebsc-1-s1.binance.org:8545/');
|
||||||
|
expect(orion.orionAnalytics.api).toBe('https://asdasd.orionprotocol.io');
|
||||||
|
expect(orion.referralSystem.api).toBe('https://zxczxc.orionprotocol.io');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Orion Responses', async () => {
|
||||||
|
const orion = new Orion('testing');
|
||||||
|
|
||||||
|
const orionUnitBSC = orion.units[SupportedChainId.BSC_TESTNET]
|
||||||
|
if (!orionUnitBSC) {
|
||||||
|
throw new Error('Orion unit not found');
|
||||||
|
}
|
||||||
|
const info = await simpleFetch(orionUnitBSC.orionBlockchain.getInfo)();
|
||||||
|
expect(info).toBeDefined();
|
||||||
|
expect(info.chainId).toBe(97);
|
||||||
|
expect(info.chainName).toBe('bsc-testnet');
|
||||||
|
|
||||||
|
const pairConfigs = await simpleFetch(orionUnitBSC.orionAggregator.getPairConfigs)('spot');
|
||||||
|
expect(pairConfigs).toBeDefined();
|
||||||
|
expect(pairConfigs.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
const aobusDone = await new Promise<boolean>((resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
reject(new Error('Timeout'));
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
orionUnitBSC.orionAggregator.ws.subscribe('aobus', {
|
||||||
|
payload: 'ORN-USDT',
|
||||||
|
callback: () => {
|
||||||
|
resolve(true);
|
||||||
|
orionUnitBSC.orionAggregator.ws.destroy();
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
expect(aobusDone).toBe(true);
|
||||||
|
// const candles = await simpleFetch(orionUnitBSC.priceFeed.getCandles)(
|
||||||
|
// 'BTC-USDT',
|
||||||
|
// Math.floor((Date.now() - 1000 * 60 * 60 * 24 * 30) / 1000), // 1 month ago
|
||||||
|
// Math.floor(Date.now() / 1000), // now
|
||||||
|
// '1d'
|
||||||
|
// );
|
||||||
|
// expect(candles).toBeDefined();
|
||||||
|
|
||||||
|
// const allTickersDone = await new Promise<boolean>((resolve, reject) => {
|
||||||
|
// const timeout = setTimeout(() => {
|
||||||
|
// reject(new Error('Timeout'));
|
||||||
|
// }, 10000);
|
||||||
|
|
||||||
|
// const { unsubscribe } = orionUnitBSC.priceFeed.ws.subscribe(
|
||||||
|
// 'allTickers',
|
||||||
|
// {
|
||||||
|
// callback: () => {
|
||||||
|
// resolve(true);
|
||||||
|
// unsubscribe();
|
||||||
|
// clearTimeout(timeout);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// });
|
||||||
|
// expect(allTickersDone).toBe(true);
|
||||||
|
|
||||||
|
// const blockNumber = await orionUnitBSC.provider.getBlockNumber();
|
||||||
|
// expect(blockNumber).toBeDefined();
|
||||||
|
// const network = await orionUnitBSC.provider.getNetwork();
|
||||||
|
// expect(network.chainId).toBe(97);
|
||||||
|
|
||||||
|
// const stats = await simpleFetch(orion.orionAnalytics.getOverview)();
|
||||||
|
// expect(stats).toBeDefined();
|
||||||
|
|
||||||
|
// const zeroAddressWithout0x = ethers.constants.AddressZero.slice(2);
|
||||||
|
// expect(simpleFetch(orion.referralSystem.getMiniStats)(zeroAddressWithout0x))
|
||||||
|
// .rejects
|
||||||
|
// .toThrow('empty reward history');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Get Orion unit by networkCode', () => {
|
||||||
|
const orionTesting = new Orion('testing');
|
||||||
|
const orionUnitBSCTesting = orionTesting.getUnit('bsc');
|
||||||
|
expect(orionUnitBSCTesting.chainId).toBe(SupportedChainId.BSC_TESTNET);
|
||||||
|
|
||||||
|
const orionMainnet = new Orion('production');
|
||||||
|
const orionUnitBSCMainnet = orionMainnet.getUnit('bsc');
|
||||||
|
expect(orionUnitBSCMainnet.chainId).toBe(SupportedChainId.BSC);
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -1,68 +1,350 @@
|
|||||||
{
|
{
|
||||||
"production": {
|
"production": {
|
||||||
|
"analyticsAPI": "https://trade.orionprotocol.io/api/stats",
|
||||||
|
"referralAPI": "https://trade.orionprotocol.io/referral-api",
|
||||||
"networks": {
|
"networks": {
|
||||||
"1": {
|
"1": {
|
||||||
"api": "https://trade.orionprotocol.io",
|
"api": "https://trade.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
},
|
||||||
"liquidityMigratorAddress": "0x23a1820a47BcD022E29f6058a5FD224242F50D1A"
|
"liquidityMigratorAddress": "0x23a1820a47BcD022E29f6058a5FD224242F50D1A"
|
||||||
},
|
},
|
||||||
"56": {
|
"56": {
|
||||||
"api": "https://trade-exp.orionprotocol.io"
|
"api": "https://trade-exp.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"250": {
|
"250": {
|
||||||
"api": "https://trade-ftm.orionprotocol.io"
|
"api": "https://trade-ftm.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"137": {
|
"137": {
|
||||||
"api": "https://trade-polygon.orionprotocol.io"
|
"api": "https://trade-polygon.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"66": {
|
"66": {
|
||||||
"api": "https://trade-okc.orionprotocol.io"
|
"api": "https://trade-okc.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"testing": {
|
"testing": {
|
||||||
|
"analyticsAPI": "https://trade.orionprotocol.io/api/stats",
|
||||||
|
"referralAPI": "https://testing.orionprotocol.io/referral-api",
|
||||||
"networks": {
|
"networks": {
|
||||||
"97": {
|
"97": {
|
||||||
"api": "https://testing.orionprotocol.io/bsc-testnet",
|
"api": "https://testing.orionprotocol.io/bsc-testnet",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
},
|
||||||
"liquidityMigratorAddress": "0x01b10dds12478C88A5E18e2707E729906bC25CfF6"
|
"liquidityMigratorAddress": "0x01b10dds12478C88A5E18e2707E729906bC25CfF6"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"api": "https://testing.orionprotocol.io/eth-ropsten",
|
"api": "https://testing.orionprotocol.io/eth-ropsten",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
},
|
||||||
"liquidityMigratorAddress": "0x36969a25622AE31bA9946e0c8151f0dc08b3A1c8"
|
"liquidityMigratorAddress": "0x36969a25622AE31bA9946e0c8151f0dc08b3A1c8"
|
||||||
},
|
},
|
||||||
"4002": {
|
"4002": {
|
||||||
"api": "https://testing.orionprotocol.io/ftm-testnet"
|
"api": "https://testing.orionprotocol.io/ftm-testnet",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"80001": {
|
"80001": {
|
||||||
"api": "https://testing.orionprotocol.io/polygon-mumbai"
|
"api": "https://testing.orionprotocol.io/polygon-mumbai",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"staging": {
|
"staging": {
|
||||||
|
"analyticsAPI": "https://trade.orionprotocol.io/api/stats",
|
||||||
|
"referralAPI": "https://staging.orionprotocol.io/referral-api",
|
||||||
"networks": {
|
"networks": {
|
||||||
"1": {
|
"1": {
|
||||||
"api": "https://staging.orionprotocol.io"
|
"api": "https://staging.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"56": {
|
"56": {
|
||||||
"api": "https://staging-bsc.orionprotocol.io"
|
"api": "https://staging-bsc.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"250": {
|
"250": {
|
||||||
"api": "https://staging-ftm.orionprotocol.io"
|
"api": "https://staging-ftm.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"137": {
|
"137": {
|
||||||
"api": "https://staging-polygon.orionprotocol.io"
|
"api": "https://staging-polygon.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"66": {
|
"66": {
|
||||||
"api": "https://staging-okc.orionprotocol.io"
|
"api": "https://staging-okc.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"experimental": {
|
"experimental": {
|
||||||
|
"analyticsAPI": "https://trade.orionprotocol.io/api/stats",
|
||||||
|
"referralAPI": "https://testing.orionprotocol.io/referral-api",
|
||||||
"networks": {
|
"networks": {
|
||||||
"97": {
|
"97": {
|
||||||
"api": "https://dn-dev.orionprotocol.io/bsc-testnet"
|
"api": "https://dn-dev.orionprotocol.io/bsc-testnet",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"api": "https://dn-dev.orionprotocol.io/eth-ropsten"
|
"api": "https://dn-dev.orionprotocol.io/eth-ropsten",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"kucoin-production": {
|
||||||
|
"analyticsAPI": "https://trade.orionprotocol.io/api/stats",
|
||||||
|
"referralAPI": "https://trade.orionprotocol.io/referral-api",
|
||||||
|
"networks": {
|
||||||
|
"1": {
|
||||||
|
"api": "https://trade.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"liquidityMigratorAddress": "0x23a1820a47BcD022E29f6058a5FD224242F50D1A"
|
||||||
|
},
|
||||||
|
"56": {
|
||||||
|
"api": "https://trade-exp.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"250": {
|
||||||
|
"api": "https://trade-ftm.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"137": {
|
||||||
|
"api": "https://trade-polygon.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"66": {
|
||||||
|
"api": "https://trade-okc.orionprotocol.io",
|
||||||
|
"services": {
|
||||||
|
"aggregator": {
|
||||||
|
"http": "/backend",
|
||||||
|
"ws": "/v1"
|
||||||
|
},
|
||||||
|
"blockchain": {
|
||||||
|
"http": ""
|
||||||
|
},
|
||||||
|
"priceFeed": {
|
||||||
|
"all": "/price-feed"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,34 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { SupportedChainId } from '../../types';
|
import { SupportedChainId } from '../../types';
|
||||||
|
|
||||||
|
export const pureEnvNetworksSchema = z.object({
|
||||||
|
api: z.string(),
|
||||||
|
services: z.object({
|
||||||
|
blockchain: z.object({
|
||||||
|
http: z.string(),
|
||||||
|
}),
|
||||||
|
aggregator: z.object({
|
||||||
|
http: z.string(),
|
||||||
|
ws: z.string(),
|
||||||
|
}),
|
||||||
|
priceFeed: z.object({
|
||||||
|
all: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
rpc: z.string().optional(),
|
||||||
|
liquidityMigratorAddress: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
export const pureEnvPayloadSchema = z.object({
|
export const pureEnvPayloadSchema = z.object({
|
||||||
|
analyticsAPI: z.string().url(),
|
||||||
|
referralAPI: z.string().url(),
|
||||||
networks: z.record(
|
networks: z.record(
|
||||||
z.nativeEnum(SupportedChainId),
|
z.nativeEnum(SupportedChainId),
|
||||||
z.object({
|
pureEnvNetworksSchema
|
||||||
api: z.string(),
|
|
||||||
rpc: z.string().optional(),
|
|
||||||
liquidityMigratorAddress: z.string().optional(),
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const pureEnvSchema = z.record(
|
export const pureEnvSchema = z.record(
|
||||||
z.string(),
|
z.enum(['production', 'staging', 'testing']).or(z.string()),
|
||||||
pureEnvPayloadSchema,
|
pureEnvPayloadSchema,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import { INTERNAL_ORION_PRECISION } from '../constants';
|
|||||||
import { CFDOrder, SignedCFDOrder, SupportedChainId } from '../types';
|
import { CFDOrder, SignedCFDOrder, 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';
|
||||||
import hashCFDOrder from "./hashCFDOrder";
|
import hashCFDOrder from './hashCFDOrder';
|
||||||
import CFD_ORDER_TYPES from "../constants/cfdOrderTypes";
|
import CFD_ORDER_TYPES from '../constants/cfdOrderTypes';
|
||||||
|
|
||||||
const DEFAULT_EXPIRATION = 29 * 24 * 60 * 60 * 1000; // 29 days
|
const DEFAULT_EXPIRATION = 29 * 24 * 60 * 60 * 1000; // 29 days
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export default async function fetchWithValidation<DataOut, DataIn, ErrorOut, Err
|
|||||||
return err({
|
return err({
|
||||||
type: 'clientErrorWithResponsePayload' as const,
|
type: 'clientErrorWithResponsePayload' as const,
|
||||||
url,
|
url,
|
||||||
message: `Client error: ${response.status} ${response.statusText}`,
|
message: `Client error: ${response.status} ${response.statusText}. Server error: ${JSON.stringify(serverError.data)}`,
|
||||||
status: response.status,
|
status: response.status,
|
||||||
payload: serverError.data,
|
payload: serverError.data,
|
||||||
});
|
});
|
||||||
@@ -125,7 +125,7 @@ export default async function fetchWithValidation<DataOut, DataIn, ErrorOut, Err
|
|||||||
return err({
|
return err({
|
||||||
type: 'clientErrorPayloadParseError' as const,
|
type: 'clientErrorPayloadParseError' as const,
|
||||||
url,
|
url,
|
||||||
message: 'Can\'t recognize error message',
|
message: 'Can\'t recognize error message. Response: ' + text,
|
||||||
status: response.status,
|
status: response.status,
|
||||||
text,
|
text,
|
||||||
error: serverError.error,
|
error: serverError.error,
|
||||||
@@ -134,7 +134,7 @@ export default async function fetchWithValidation<DataOut, DataIn, ErrorOut, Err
|
|||||||
return err({
|
return err({
|
||||||
type: 'clientError' as const,
|
type: 'clientError' as const,
|
||||||
url,
|
url,
|
||||||
message: `Error: ${response.status} ${response.statusText}`,
|
message: `Error: ${response.status} ${response.statusText}. Response: ${text}`,
|
||||||
status: response.status,
|
status: response.status,
|
||||||
text,
|
text,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ BigNumber.config({ EXPONENTIAL_AT: 1e+9 });
|
|||||||
|
|
||||||
export * as config from './config';
|
export * as config from './config';
|
||||||
export { default as OrionUnit } from './OrionUnit';
|
export { default as OrionUnit } from './OrionUnit';
|
||||||
|
export { default as Orion } from './Orion';
|
||||||
export { default as initOrionUnit } from './initOrionUnit';
|
export { default as initOrionUnit } from './initOrionUnit';
|
||||||
export { default as fetchWithValidation } from './fetchWithValidation';
|
export { default as fetchWithValidation } from './fetchWithValidation';
|
||||||
export { default as simpleFetch } from './simpleFetch';
|
export { default as simpleFetch } from './simpleFetch';
|
||||||
|
|||||||
@@ -9,22 +9,36 @@ 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 { Exchange, SignedCancelOrderRequest, SignedCFDOrder, 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 networkCodes from '../../constants/networkCodes';
|
||||||
import toUpperCase from '../../utils/toUpperCase';
|
import toUpperCase from '../../utils/toUpperCase';
|
||||||
|
import httpToWS from '../../utils/httpToWS';
|
||||||
|
|
||||||
class OrionAggregator {
|
class OrionAggregator {
|
||||||
private readonly apiUrl: string;
|
private readonly apiUrl: string;
|
||||||
|
|
||||||
readonly ws: OrionAggregatorWS;
|
readonly ws: OrionAggregatorWS;
|
||||||
|
|
||||||
constructor(apiUrl: string, apiWsUrl: string) {
|
get api() {
|
||||||
this.apiUrl = apiUrl;
|
return this.apiUrl;
|
||||||
this.ws = new OrionAggregatorWS(apiWsUrl);
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
httpAPIUrl: string,
|
||||||
|
wsAPIUrl: string,
|
||||||
|
) {
|
||||||
|
// const oaUrl = new URL(apiUrl);
|
||||||
|
// const oaWsProtocol = oaUrl.protocol === 'https:' ? 'wss' : 'ws';
|
||||||
|
// const orionAggregatorWsUrl = `${oaWsProtocol}://${oaUrl.host + (oaUrl.pathname === '/'
|
||||||
|
// ? ''
|
||||||
|
// : oaUrl.pathname)}/v1`;
|
||||||
|
|
||||||
|
this.apiUrl = httpAPIUrl;
|
||||||
|
this.ws = new OrionAggregatorWS(httpToWS(wsAPIUrl));
|
||||||
|
|
||||||
this.getHistoryAtomicSwaps = this.getHistoryAtomicSwaps.bind(this);
|
this.getHistoryAtomicSwaps = this.getHistoryAtomicSwaps.bind(this);
|
||||||
this.getPairConfig = this.getPairConfig.bind(this);
|
this.getPairConfig = this.getPairConfig.bind(this);
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ type SwapInfoSubscription = {
|
|||||||
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>
|
||||||
}
|
}
|
||||||
@@ -79,10 +79,10 @@ type AddressUpdateUpdate = {
|
|||||||
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?: z.infer<typeof fullOrderSchema>[] // The field is not defined if the user has no orders
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,23 @@ const exclusiveSubscriptions = [
|
|||||||
SubscriptionType.ASSET_PAIRS_CONFIG_UPDATES_SUBSCRIBE,
|
SubscriptionType.ASSET_PAIRS_CONFIG_UPDATES_SUBSCRIBE,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
type WsMessage = string | ArrayBufferLike | Blob | ArrayBufferView;
|
type BufferLike =
|
||||||
|
| string
|
||||||
|
| Buffer
|
||||||
|
| DataView
|
||||||
|
| number
|
||||||
|
| ArrayBufferView
|
||||||
|
| Uint8Array
|
||||||
|
| ArrayBuffer
|
||||||
|
| SharedArrayBuffer
|
||||||
|
| ReadonlyArray<unknown>
|
||||||
|
| ReadonlyArray<number>
|
||||||
|
| { valueOf(): ArrayBuffer }
|
||||||
|
| { valueOf(): SharedArrayBuffer }
|
||||||
|
| { valueOf(): Uint8Array }
|
||||||
|
| { valueOf(): ReadonlyArray<number> }
|
||||||
|
| { valueOf(): 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 {
|
||||||
@@ -148,14 +164,23 @@ class OrionAggregatorWS {
|
|||||||
|
|
||||||
private readonly wsUrl: string;
|
private readonly wsUrl: string;
|
||||||
|
|
||||||
constructor(wsUrl: string, logger?: (msg: string) => void, onInit?: () => void, onError?: (err: string) => void) {
|
get api() {
|
||||||
|
return this.wsUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
wsUrl: string,
|
||||||
|
logger?: (msg: string) => void,
|
||||||
|
onInit?: () => void,
|
||||||
|
onError?: (err: string) => void
|
||||||
|
) {
|
||||||
this.wsUrl = wsUrl;
|
this.wsUrl = wsUrl;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.onInit = onInit;
|
this.onInit = onInit;
|
||||||
this.onError = onError;
|
this.onError = onError;
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendRaw(data: WsMessage) {
|
private sendRaw(data: BufferLike) {
|
||||||
if (this.ws?.readyState === 1) {
|
if (this.ws?.readyState === 1) {
|
||||||
this.ws.send(data);
|
this.ws.send(data);
|
||||||
} else if (this.ws?.readyState === 0) {
|
} else if (this.ws?.readyState === 0) {
|
||||||
@@ -167,7 +192,9 @@ class OrionAggregatorWS {
|
|||||||
|
|
||||||
private send(data: unknown) {
|
private send(data: unknown) {
|
||||||
if (this.ws?.readyState === 1) {
|
if (this.ws?.readyState === 1) {
|
||||||
this.ws.send(JSON.stringify(data));
|
const jsonData = JSON.stringify(data);
|
||||||
|
this.ws.send(jsonData);
|
||||||
|
this.logger?.(`Sent: ${jsonData}`);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.send(data);
|
this.send(data);
|
||||||
@@ -268,7 +295,7 @@ class OrionAggregatorWS {
|
|||||||
delete this.ws;
|
delete this.ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
init(isReconnect = false) {
|
private init(isReconnect = false) {
|
||||||
this.isClosedIntentionally = false;
|
this.isClosedIntentionally = false;
|
||||||
this.ws = new WebSocket(this.wsUrl);
|
this.ws = new WebSocket(this.wsUrl);
|
||||||
this.ws.onerror = (err) => {
|
this.ws.onerror = (err) => {
|
||||||
@@ -455,7 +482,7 @@ class OrionAggregatorWS {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
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
|
||||||
@@ -494,7 +521,6 @@ class OrionAggregatorWS {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case MessageType.ADDRESS_UPDATE: {
|
case MessageType.ADDRESS_UPDATE: {
|
||||||
const balances = json.b
|
const balances = json.b
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from 'zod';
|
||||||
import { fullOrderSchema, orderUpdateSchema } from "./addressUpdateSchema";
|
import { fullOrderSchema, orderUpdateSchema } from './addressUpdateSchema';
|
||||||
import baseMessageSchema from "./baseMessageSchema";
|
import baseMessageSchema from './baseMessageSchema';
|
||||||
import MessageType from "../MessageType";
|
import MessageType from '../MessageType';
|
||||||
import cfdBalancesSchema from "./cfdBalancesSchema";
|
import cfdBalancesSchema from './cfdBalancesSchema';
|
||||||
|
|
||||||
const baseCfdAddressUpdate = baseMessageSchema.extend({
|
const baseCfdAddressUpdate = baseMessageSchema.extend({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import positionStatuses from "../../../../constants/positionStatuses";
|
import positionStatuses from '../../../../constants/positionStatuses';
|
||||||
|
|
||||||
const cfdBalanceSchema = z
|
const cfdBalanceSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
|||||||
@@ -10,8 +10,12 @@ export default class OrionAnalytics {
|
|||||||
this.getOverview = this.getOverview.bind(this);
|
this.getOverview = this.getOverview.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get api() {
|
||||||
|
return this.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
getOverview = () => fetchWithValidation(
|
getOverview = () => fetchWithValidation(
|
||||||
`${this.apiUrl}/api/stats/overview`,
|
`${this.apiUrl}/overview`,
|
||||||
overviewSchema,
|
overviewSchema,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ type CfdHistoryQuery = {
|
|||||||
class OrionBlockchain {
|
class OrionBlockchain {
|
||||||
private readonly apiUrl: string;
|
private readonly apiUrl: string;
|
||||||
|
|
||||||
|
get api() {
|
||||||
|
return this.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(apiUrl: string) {
|
constructor(apiUrl: string) {
|
||||||
this.apiUrl = apiUrl;
|
this.apiUrl = apiUrl;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ class PriceFeed {
|
|||||||
|
|
||||||
readonly ws: PriceFeedWS;
|
readonly ws: PriceFeedWS;
|
||||||
|
|
||||||
|
get api() {
|
||||||
|
return this.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(apiUrl: string) {
|
constructor(apiUrl: string) {
|
||||||
this.apiUrl = apiUrl;
|
this.apiUrl = apiUrl;
|
||||||
this.ws = new PriceFeedWS(this.wsUrl);
|
this.ws = new PriceFeedWS(this.wsUrl);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
import fetchWithValidation from '../../fetchWithValidation';
|
import fetchWithValidation from '../../fetchWithValidation';
|
||||||
import { errorSchema, miniStatsSchema, rewardsMappingSchema } from './schemas';
|
import { errorSchema, miniStatsSchema, rewardsMappingSchema } from './schemas';
|
||||||
import distinctAnalyticsSchema from './schemas/distinctAnalyticsSchema';
|
import distinctAnalyticsSchema from './schemas/distinctAnalyticsSchema';
|
||||||
@@ -21,8 +22,12 @@ type SignatureType = {
|
|||||||
class ReferralSystem {
|
class ReferralSystem {
|
||||||
private apiUrl: string;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(apiUrl: string, env: string) {
|
get api() {
|
||||||
this.apiUrl = ReferralSystem.getActualApiUrl(apiUrl, env);
|
return this.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(apiUrl: string) {
|
||||||
|
this.apiUrl = apiUrl;
|
||||||
|
|
||||||
this.getLink = this.getLink.bind(this);
|
this.getLink = this.getLink.bind(this);
|
||||||
this.getDistinctAnalytics = this.getDistinctAnalytics.bind(this);
|
this.getDistinctAnalytics = this.getDistinctAnalytics.bind(this);
|
||||||
@@ -31,19 +36,6 @@ class ReferralSystem {
|
|||||||
this.getMyReferral = this.getMyReferral.bind(this);
|
this.getMyReferral = this.getMyReferral.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ресурсы реферальной системы в тестинг окружении имеют вид
|
|
||||||
// testing.orionprotocol.io/referral-api вместо обычного
|
|
||||||
// testing.orionprotocol.io/bsc-testnet/referral-api, поэтому лишняя часть вырезается
|
|
||||||
static getActualApiUrl = (apiUrl: string, env: string) => {
|
|
||||||
if (env === 'testing' || env === 'custom') {
|
|
||||||
const { protocol, hostname } = new URL(apiUrl);
|
|
||||||
|
|
||||||
return `${protocol}//${hostname}/referral-api`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${apiUrl}/referral-api`;
|
|
||||||
};
|
|
||||||
|
|
||||||
getLink = (refererAddress: string) => fetchWithValidation(`${this.apiUrl}/referer/view/link`, linkSchema, {
|
getLink = (refererAddress: string) => fetchWithValidation(`${this.apiUrl}/referer/view/link`, linkSchema, {
|
||||||
headers: {
|
headers: {
|
||||||
'referer-address': refererAddress,
|
'referer-address': refererAddress,
|
||||||
@@ -76,6 +68,9 @@ class ReferralSystem {
|
|||||||
globalAnalyticsSchema,
|
globalAnalyticsSchema,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param refererAddress Address without 0x prefix
|
||||||
|
*/
|
||||||
getMiniStats = (refererAddress: string) => fetchWithValidation(
|
getMiniStats = (refererAddress: string) => fetchWithValidation(
|
||||||
`${this.apiUrl}/referer/view/mini-latest-stats`,
|
`${this.apiUrl}/referer/view/mini-latest-stats`,
|
||||||
miniStatsSchema,
|
miniStatsSchema,
|
||||||
@@ -84,6 +79,10 @@ class ReferralSystem {
|
|||||||
'referer-address': refererAddress,
|
'referer-address': refererAddress,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
z.object({
|
||||||
|
status: z.string(),
|
||||||
|
message: z.string(),
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
getRewardsMapping = (referralAddress: string) => fetchWithValidation(
|
getRewardsMapping = (referralAddress: string) => fetchWithValidation(
|
||||||
|
|||||||
57
src/types.ts
57
src/types.ts
@@ -3,20 +3,24 @@ import exchanges from './constants/exchanges';
|
|||||||
import subOrderStatuses from './constants/subOrderStatuses';
|
import subOrderStatuses from './constants/subOrderStatuses';
|
||||||
import positionStatuses from './constants/positionStatuses';
|
import positionStatuses from './constants/positionStatuses';
|
||||||
|
|
||||||
|
export type DeepPartial<T> = T extends object ? {
|
||||||
|
[P in keyof T]?: DeepPartial<T[P]>;
|
||||||
|
} : 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 = {
|
||||||
@@ -238,3 +242,34 @@ export enum HistoryTransactionStatus {
|
|||||||
APPROVING = 'Approving',
|
APPROVING = 'Approving',
|
||||||
CANCELLED = 'Cancelled',
|
CANCELLED = 'Cancelled',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type VerboseOrionUnitConfig = {
|
||||||
|
// env?: string;
|
||||||
|
// api: string;
|
||||||
|
chainId: SupportedChainId;
|
||||||
|
nodeJsonRpc: string;
|
||||||
|
services: {
|
||||||
|
orionBlockchain: {
|
||||||
|
http: string;
|
||||||
|
// For example:
|
||||||
|
// http://localhost:3001/,
|
||||||
|
// http://10.123.34.23:3001/,
|
||||||
|
// https://blockchain.orionprotocol.io/
|
||||||
|
},
|
||||||
|
orionAggregator: {
|
||||||
|
http: string;
|
||||||
|
ws: string;
|
||||||
|
// For example:
|
||||||
|
// http://localhost:3002/,
|
||||||
|
// http://10.34.23.5:3002/,
|
||||||
|
// shttps://aggregator.orionprotocol.io/
|
||||||
|
},
|
||||||
|
priceFeed: {
|
||||||
|
api: string;
|
||||||
|
// For example:
|
||||||
|
// http://localhost:3003/,
|
||||||
|
// http://10.23.5.11:3003/,
|
||||||
|
// https://price-feed.orionprotocol.io/
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const arrayEquals = (a: unknown[], b: unknown[]) => a.length === b.length
|
const arrayEquals = (a: unknown[], b: unknown[]) => a.length === b.length &&
|
||||||
&& a.every((value, index) => value === b[index]);
|
a.every((value, index) => value === b[index]);
|
||||||
|
|
||||||
export default arrayEquals;
|
export default arrayEquals;
|
||||||
|
|||||||
17
src/utils/httpToWS.ts
Normal file
17
src/utils/httpToWS.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const httpToWS = (url: string) => {
|
||||||
|
let parsedUrl: URL;
|
||||||
|
try {
|
||||||
|
parsedUrl = new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`httpToWS: Invalid URL ${url}`);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
if (parsedUrl.protocol === 'https:') {
|
||||||
|
parsedUrl.protocol = 'wss:';
|
||||||
|
} else if (parsedUrl.protocol === 'http:') {
|
||||||
|
parsedUrl.protocol = 'ws:';
|
||||||
|
}
|
||||||
|
return parsedUrl.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default httpToWS;
|
||||||
@@ -9,6 +9,6 @@ export default function isNetworkCodeInEnvironment(networkCode: string, env: str
|
|||||||
if (envNetworks === undefined) throw new Error('Env networks is undefined (isNetworkCodeInEnvironment)');
|
if (envNetworks === undefined) 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() &&
|
||||||
&& chain.chainId in envNetworks);
|
chain.chainId in envNetworks);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
|
// "extends": "@tsconfig/strictest/tsconfig.json",
|
||||||
"files": [
|
"files": [
|
||||||
"./src/index.ts"
|
"./src/index.ts"
|
||||||
],
|
],
|
||||||
"include": [
|
"include": [
|
||||||
"./src/**/*.ts"
|
"./src/**/*.ts",
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"**/__tests__/*",
|
// "**/__tests__/*",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
|||||||
Reference in New Issue
Block a user