diff --git a/package-lock.json b/package-lock.json index 778239e..5d8e6fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.92-rc2", + "version": "0.20.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@orionprotocol/sdk", - "version": "0.19.92-rc2", + "version": "0.20.2", "hasInstallScript": true, "license": "ISC", "dependencies": { @@ -622,54 +622,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-arm64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", @@ -686,294 +638,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", diff --git a/package.json b/package.json index aa1ba69..e0c8749 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.1", + "version": "0.20.2", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Orion/index.ts b/src/Orion/index.ts index 80dbbf1..b2a6b44 100644 --- a/src/Orion/index.ts +++ b/src/Orion/index.ts @@ -58,6 +58,9 @@ export default class Orion { priceFeed: { api: networkConfig.api + networkConfig.services.priceFeed.all, }, + integrator: { + api: networkConfig.api + networkConfig.services.integrator.http, + } }, }; }) diff --git a/src/Unit/index.ts b/src/Unit/index.ts index e0ea40f..5fd9e87 100644 --- a/src/Unit/index.ts +++ b/src/Unit/index.ts @@ -1,21 +1,25 @@ -import { ethers } from 'ethers'; +import { JsonRpcProvider } from 'ethers'; import { Aggregator } from '../services/Aggregator/index.js'; import { BlockchainService } from '../services/BlockchainService/index.js'; import { PriceFeed } from '../services/PriceFeed/index.js'; -import type { KnownEnv, SupportedChainId, VerboseUnitConfig } from '../types.js'; +import type { + KnownEnv, + SupportedChainId, + VerboseUnitConfig, +} from '../types.js'; import Exchange from './Exchange/index.js'; import FarmingManager from './FarmingManager/index.js'; import { chains, envs } from '../config/index.js'; import type { networkCodes } from '../constants/index.js'; -import type { JsonRpcProvider } from 'ethers'; +import { IntegratorService } from '../services/Integrator/index.js'; type KnownConfig = { env: KnownEnv chainId: SupportedChainId -} +}; export default class Unit { - public readonly networkCode: typeof networkCodes[number]; + public readonly networkCode: (typeof networkCodes)[number]; public readonly chainId: SupportedChainId; @@ -23,6 +27,8 @@ export default class Unit { public readonly blockchainService: BlockchainService; + public readonly integrator: IntegratorService; + public readonly aggregator: Aggregator; public readonly priceFeed: PriceFeed; @@ -38,13 +44,33 @@ export default class Unit { constructor(config: KnownConfig | VerboseUnitConfig) { if ('env' in config) { const staticConfig = envs[config.env]; - if (!staticConfig) throw new Error(`Invalid environment: ${config.env}. Available environments: ${Object.keys(envs).join(', ')}`); + if (!staticConfig) { + throw new Error( + `Invalid environment: ${ + config.env + }. Available environments: ${Object.keys(envs).join(', ')}` + ); + } const chainConfig = chains[config.chainId]; - if (!chainConfig) throw new Error(`Invalid chainId: ${config.chainId}. Available chainIds: ${Object.keys(chains).join(', ')}`); + if (!chainConfig) { + throw new Error( + `Invalid chainId: ${ + config.chainId + }. Available chainIds: ${Object.keys(chains).join(', ')}` + ); + } const networkConfig = staticConfig.networks[config.chainId]; - if (!networkConfig) throw new Error(`Invalid chainId: ${config.chainId}. Available chainIds: ${Object.keys(staticConfig.networks).join(', ')}`); + if (!networkConfig) { + throw new Error( + `Invalid chainId: ${ + config.chainId + }. Available chainIds: ${Object.keys(staticConfig.networks).join( + ', ' + )}` + ); + } this.config = { chainId: config.chainId, nodeJsonRpc: networkConfig.rpc ?? chainConfig.rpc, @@ -59,8 +85,11 @@ export default class Unit { priceFeed: { api: networkConfig.api + networkConfig.services.priceFeed.all, }, + integrator: { + api: networkConfig.api + networkConfig.services.integrator.http, + }, }, - } + }; } else { this.config = config; } @@ -68,19 +97,31 @@ export default class Unit { if (!chainInfo) throw new Error('Chain info is required'); this.chainId = config.chainId; this.networkCode = chainInfo.code; - this.contracts = chainInfo.contracts + this.contracts = chainInfo.contracts; const intNetwork = parseInt(this.chainId, 10); - if (Number.isNaN(intNetwork)) throw new Error('Invalid chainId (not a number)' + this.chainId); - this.provider = new ethers.JsonRpcProvider(this.config.nodeJsonRpc, intNetwork); + if (Number.isNaN(intNetwork)) { + throw new Error('Invalid chainId (not a number)' + this.chainId); + } + this.provider = new JsonRpcProvider(this.config.nodeJsonRpc, intNetwork); this.provider.pollingInterval = 1000; - this.blockchainService = new BlockchainService(this.config.services.blockchainService.http, this.config.basicAuth); + this.blockchainService = new BlockchainService( + this.config.services.blockchainService.http, + this.config.basicAuth + ); + this.integrator = new IntegratorService( + this.config.services.integrator.api, + intNetwork + ); this.aggregator = new Aggregator( this.config.services.aggregator.http, this.config.services.aggregator.ws, - this.config.basicAuth, + this.config.basicAuth + ); + this.priceFeed = new PriceFeed( + this.config.services.priceFeed.api, + this.config.basicAuth ); - this.priceFeed = new PriceFeed(this.config.services.priceFeed.api, this.config.basicAuth); this.exchange = new Exchange(this); this.farmingManager = new FarmingManager(this); } diff --git a/src/__tests__/basic.test.ts b/src/__tests__/basic.test.ts index 0643669..7967396 100644 --- a/src/__tests__/basic.test.ts +++ b/src/__tests__/basic.test.ts @@ -177,6 +177,9 @@ describe('Orion', () => { priceFeed: { api: orionPriceFeedAPI + '/price-feed', }, + integrator: { + api: '', + } }, } } diff --git a/src/config/envs.json b/src/config/envs.json index 1c193bf..8359aa9 100644 --- a/src/config/envs.json +++ b/src/config/envs.json @@ -15,6 +15,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } }, "liquidityMigratorAddress": "0x23a1820a47BcD022E29f6058a5FD224242F50D1A" @@ -31,6 +34,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -46,6 +52,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -61,6 +70,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -76,6 +88,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } } @@ -97,6 +112,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } }, "liquidityMigratorAddress": "0x01b10dds12478C88A5E18e2707E729906bC25CfF6" @@ -113,6 +131,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -128,6 +149,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -143,6 +167,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -158,6 +185,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -173,6 +203,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } } @@ -194,6 +227,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -209,6 +245,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -224,6 +263,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -239,6 +281,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -254,6 +299,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } } @@ -275,6 +323,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -290,6 +341,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } } @@ -311,6 +365,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } }, "liquidityMigratorAddress": "0x23a1820a47BcD022E29f6058a5FD224242F50D1A" @@ -327,6 +384,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -342,6 +402,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -357,6 +420,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } }, @@ -372,6 +438,9 @@ }, "priceFeed": { "all": "/price-feed" + }, + "integrator": { + "http": "/orion-integrator/" } } } diff --git a/src/config/schemas/pureEnvSchema.ts b/src/config/schemas/pureEnvSchema.ts index 8838cd5..854e9f4 100644 --- a/src/config/schemas/pureEnvSchema.ts +++ b/src/config/schemas/pureEnvSchema.ts @@ -14,6 +14,9 @@ export const pureEnvNetworksSchema = z.object({ priceFeed: z.object({ all: z.string(), }), + integrator: z.object({ + http: z.string(), + }), }), rpc: z.string().optional(), liquidityMigratorAddress: z.string().optional(), diff --git a/src/constants/index.ts b/src/constants/index.ts index c414279..efe47f0 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -9,5 +9,6 @@ export { default as exchangesMap } from './exchangesMap.js'; export * from './chains.js'; export * from './precisions.js'; export * from './gasLimits.js'; +export * from './timings.js'; export const SERVICE_TOKEN = 'ORN'; diff --git a/src/constants/timings.ts b/src/constants/timings.ts new file mode 100644 index 0000000..471091e --- /dev/null +++ b/src/constants/timings.ts @@ -0,0 +1,3 @@ +export const DAY = 86400 +export const WEEK_DAYS = 7; +export const YEAR = 365 * DAY diff --git a/src/services/BlockchainService/index.ts b/src/services/BlockchainService/index.ts index 6c43a0a..e301615 100644 --- a/src/services/BlockchainService/index.ts +++ b/src/services/BlockchainService/index.ts @@ -61,8 +61,8 @@ type AtomicSwapHistoryTargetQuery = AtomicSwapHistoryBaseQuery & { } type PlatformFees = { - assetIn: string - assetOut: string + assetIn?: string // TODO: return types from main branch + assetOut?: string walletAddress?: string | undefined fromWidget?: string | undefined } @@ -247,8 +247,13 @@ class BlockchainService { ) => { const url = new URL(`${this.apiUrl}/api/platform-fees`); - url.searchParams.append('assetIn', assetIn); - url.searchParams.append('assetOut', assetOut); + if (assetIn !== undefined) { // TODO: make same as in main branch + url.searchParams.append('assetIn', assetIn); + } + + if (assetOut !== undefined) { + url.searchParams.append('assetOut', assetOut); + } if (walletAddress !== undefined) { url.searchParams.append('walletAddress', walletAddress); diff --git a/src/services/Integrator/constants.ts b/src/services/Integrator/constants.ts new file mode 100644 index 0000000..8ec49a1 --- /dev/null +++ b/src/services/Integrator/constants.ts @@ -0,0 +1,3 @@ +export const AVAILABLE_POOL_FEE = ['0.01', '0.05', '0.3', '1'] as const; +export const INITIAL_VEORN_ADJUSTMENT_FACTOR = 5; +export const LOCK_START_TIME = 1690848000;// Aug 01 2023 00:00:00 UTC diff --git a/src/services/Integrator/index.ts b/src/services/Integrator/index.ts new file mode 100644 index 0000000..43be3fb --- /dev/null +++ b/src/services/Integrator/index.ts @@ -0,0 +1,223 @@ +import { + environmentResponseSchema, + getPoolResponseSchema, + listAmountResponseSchema, + listNFTOrderResponseSchema, + listPoolResponseSchema, + testIncrementorSchema, + veORNInfoResponseSchema, + votingInfoResponseSchema +} from './schemas/index.js'; +import { fetchWithValidation } from 'simple-typed-fetch'; +import { BigNumber } from 'bignumber.js'; +import { DAY, WEEK_DAYS, YEAR } from '../../constants/index.js'; +import { LOCK_START_TIME } from './constants.js'; + +type BasePayload = { + chainId: number + jsonrpc: '1.0' +}; + +type GetEnvironmentPayload = BasePayload & { + model: 'Environment' + method: 'getEnvironment' + params: [] +}; + +type ListNFTOrderPayload = BasePayload & { + model: 'OrionV3NFTManager' + method: 'listNFTOrder' + params: [string] +}; + +type GetPoolInfoPayload = BasePayload & { + model: 'OrionV3Factory' + method: 'getPoolInfo' + params: [string, string, string] +}; + +type ListPoolPayload = BasePayload & { + model: 'OrionFarmV3' + method: 'listPool' + params: [string] +}; + +type VeORNInfoPayload = BasePayload & { + model: 'veORN' + method: 'info' + params: [string] +} + +type ListAmountPayload = BasePayload & { + model: string + method: 'listAmount' + params: [] +} + +type GetAmountByORNPayload = BasePayload & { + amountToken: number + timeLock: number +} + +type Payload = + | GetEnvironmentPayload + | ListNFTOrderPayload + | GetPoolInfoPayload + | ListPoolPayload + | VeORNInfoPayload + | ListAmountPayload + | GetAmountByORNPayload; + +class IntegratorService { + private readonly apiUrl: string; + + private readonly chainId: number; + + get api() { + return this.apiUrl; + } + + constructor(apiUrl: string, chainId: number) { + this.apiUrl = apiUrl; + this.chainId = chainId; + + this.getEnvironment = this.getEnvironment.bind(this); + this.listNFTOrder = this.listNFTOrder.bind(this); + this.getPoolInfo = this.getPoolInfo.bind(this); + this.listPool = this.listPool.bind(this); + this.veORNInfo = this.veORNInfo.bind(this); + this.listAmount = this.listAmount.bind(this); + this.getAmountByORN = this.getAmountByORN.bind(this); + this.getAmountAtCurrent = this.getAmountAtCurrent.bind(this); + this.getVotingInfo = this.getVotingInfo.bind(this); + } + + readonly makeRPCPayload = (payload: Omit) => { + return JSON.stringify({ + ...payload, + chainId: this.chainId, + jsonrpc: '1.0', + }); + }; + + readonly veORNInfo = (address: string) => { + return fetchWithValidation(this.apiUrl, veORNInfoResponseSchema, { + method: 'POST', + body: this.makeRPCPayload({ + model: 'veORN', + method: 'info', + params: [address] + }) + }) + } + + readonly getAmountAtCurrent = (amount: number): BigNumber => { + const timestamp = Date.now() / 1000; + + // sqrt + return BigNumber(amount).dividedBy(this.getK(timestamp)); + } + + readonly getVotingInfo = (userAddress: string) => { + return fetchWithValidation(this.apiUrl, votingInfoResponseSchema, { + method: 'POST', + body: this.makeRPCPayload({ + model: 'OrionVoting', + method: 'info', + params: [userAddress], + }), + }); + } + + readonly getEnvironment = () => { + return fetchWithValidation(this.apiUrl, environmentResponseSchema, { + method: 'POST', + body: this.makeRPCPayload({ + model: 'Environment', + method: 'getEnvironment', + params: [], + }), + }); + }; + + readonly listNFTOrder = (address: string) => { + return fetchWithValidation(this.apiUrl, listNFTOrderResponseSchema, { + method: 'POST', + body: this.makeRPCPayload({ + model: 'OrionV3NFTManager', + method: 'listNFTOrder', + params: [address], + }), + }); + }; + + readonly getPoolInfo = ( + token0: string, + token1: string, + poolAddress: string + ) => { + return fetchWithValidation(this.apiUrl, getPoolResponseSchema, { + method: 'POST', + body: this.makeRPCPayload({ + model: 'OrionV3Factory', + method: 'getPoolInfo', + params: [token0, token1, poolAddress], + }), + }); + } + + readonly listPool = (address: string) => { + return fetchWithValidation(this.apiUrl, listPoolResponseSchema, { + method: 'POST', + body: this.makeRPCPayload({ + model: 'OrionFarmV3', + method: 'listPool', + params: [address], + }), + }); + } + + readonly listAmount = (poolKey: string) => { + return fetchWithValidation(this.apiUrl, listAmountResponseSchema, { + method: 'POST', + body: this.makeRPCPayload({ + model: poolKey, + method: 'listAmount', + params: [], + }), + }); + } + + readonly testRetrieve = () => { + return fetchWithValidation(this.apiUrl, testIncrementorSchema, { + method: 'POST', + body: this.makeRPCPayload({ + model: 'Incrementer', + method: 'retrieve', + params: [], + }), + }); + } + + private readonly getK = (time: number) => { + const currentTime = time < LOCK_START_TIME ? LOCK_START_TIME : time; + + const deltaYears = BigNumber(currentTime).minus(LOCK_START_TIME).dividedBy(YEAR); + return 2 ** BigNumber(deltaYears).multipliedBy(2).toNumber(); + } + + private readonly getAmountByORN = (amountToken: number, timeLock: number) => { + const timestamp = Date.now() / 1000; + + const deltaDays = BigNumber(timeLock).minus(timestamp).dividedBy(DAY); + if (deltaDays.lt(0)) { + return 0; + } + + // sqrt + return BigNumber(amountToken).multipliedBy(BigNumber(deltaDays).sqrt()).dividedBy(BigNumber(WEEK_DAYS).sqrt()); + } +} + +export * as schemas from './schemas/index.js'; +export { IntegratorService }; diff --git a/src/services/Integrator/schemas/basic-pool-info-schema.ts b/src/services/Integrator/schemas/basic-pool-info-schema.ts new file mode 100644 index 0000000..049c92f --- /dev/null +++ b/src/services/Integrator/schemas/basic-pool-info-schema.ts @@ -0,0 +1,26 @@ +import { z } from 'zod'; +import { evmAddressSchema } from './util-schemas.js'; + +const basicPoolInfo = z.object({ + poolAddress: evmAddressSchema, + isInitialized: z.boolean(), + liquidity: z.number().nonnegative(), + liquidityInUsd: z.number().nonnegative(), + liquidityShare: z.number().nonnegative(), + isFarming: z.boolean(), + rewardsTotal: z.number().nonnegative(), + rewardsPerPeriod: z.number().nonnegative(), + rewardsShare: z.number().nonnegative(), + feePerPeriod: z.number().nonnegative(), + feeTotal: z.number().nonnegative(), + feeShare: z.number().nonnegative(), + tickMultiplier: z.number().nonnegative(), + MAX_TICK: z.number().nonnegative().int(), + minAPR: z.number().nonnegative(), + maxAPR: z.number().nonnegative(), + avgAPR: z.number().nonnegative(), + maxBoost: z.number().nonnegative().int(), + feeRate: z.array(z.number().nonnegative()), +}); + +export default basicPoolInfo; diff --git a/src/services/Integrator/schemas/environment-response-schema.ts b/src/services/Integrator/schemas/environment-response-schema.ts new file mode 100644 index 0000000..5da5cd2 --- /dev/null +++ b/src/services/Integrator/schemas/environment-response-schema.ts @@ -0,0 +1,19 @@ +import { z } from 'zod'; +import { evmAddressSchema } from './util-schemas.js'; +import infoSchema from './info-schema.js'; + +const environmentResponseSchema = z.object({ + result: z.object({ + chainId: z.number().int().nonnegative(), + nativeToken: z.string(), + OrionV3Factory: evmAddressSchema, + OrionV3NFTManager: evmAddressSchema, + SwapRouter: evmAddressSchema, + OrionFarmV3: evmAddressSchema, + OrionVoting: evmAddressSchema, + veORN: evmAddressSchema, + }), + info: infoSchema, +}); + +export default environmentResponseSchema; diff --git a/src/services/Integrator/schemas/get-pool-response-schema.ts b/src/services/Integrator/schemas/get-pool-response-schema.ts new file mode 100644 index 0000000..ee49682 --- /dev/null +++ b/src/services/Integrator/schemas/get-pool-response-schema.ts @@ -0,0 +1,21 @@ +import { z } from 'zod'; +import { evmAddressSchema } from './util-schemas.js'; +import { AVAILABLE_POOL_FEE } from '../constants.js'; +import basicPoolInfo from './basic-pool-info-schema.js'; +import infoSchema from './info-schema.js'; + +const getPoolResponseSchema = z.object({ + result: z.object({ + token0: z.string().nonempty(), + token1: z.string().nonempty(), + token0Address: evmAddressSchema, + token1Address: evmAddressSchema, + + totalLiquidity: z.number().nonnegative(), + WETH9: evmAddressSchema, + pools: z.record(z.enum(AVAILABLE_POOL_FEE), basicPoolInfo.nullable()), + }), + info: infoSchema, +}); + +export default getPoolResponseSchema; diff --git a/src/services/Integrator/schemas/index.ts b/src/services/Integrator/schemas/index.ts new file mode 100644 index 0000000..e6e03b6 --- /dev/null +++ b/src/services/Integrator/schemas/index.ts @@ -0,0 +1,8 @@ +export { default as environmentResponseSchema } from './environment-response-schema.js'; +export { default as listNFTOrderResponseSchema } from './list-nft-order-response-schema.js'; +export { default as getPoolResponseSchema } from './get-pool-response-schema.js'; +export { default as listPoolResponseSchema } from './list-pool-response-schema.js'; +export { default as veORNInfoResponseSchema } from './veORN-info-schema.js'; +export { default as listAmountResponseSchema } from './list-amount-schema.js'; +export { default as votingInfoResponseSchema } from './voting-info-schema.js'; +export { default as testIncrementorSchema } from './test-incrementor-schema.js'; diff --git a/src/services/Integrator/schemas/info-schema.ts b/src/services/Integrator/schemas/info-schema.ts new file mode 100644 index 0000000..9e1dc60 --- /dev/null +++ b/src/services/Integrator/schemas/info-schema.ts @@ -0,0 +1,14 @@ +import { z } from 'zod'; +import { ethers } from 'ethers'; + +const infoSchema = z.object({ + blockNumber: z.number().int().nonnegative(), + blockHash: z.string().refine((v) => v.length === 0 || ethers.utils.isHexString(v), { + message: 'blockHash must be a valid hex string or empty', + }), + timeRequest: z.number().int().nonnegative(), + timeAnswer: z.number().int().nonnegative(), + changes: z.number().int().nonnegative(), +}); + +export default infoSchema; diff --git a/src/services/Integrator/schemas/list-amount-schema.ts b/src/services/Integrator/schemas/list-amount-schema.ts new file mode 100644 index 0000000..d942a51 --- /dev/null +++ b/src/services/Integrator/schemas/list-amount-schema.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; +import infoSchema from './info-schema.js'; + +const listAmountSchema = z.object({ + result: z.record(z.number()), + info: infoSchema, +}); + +export default listAmountSchema; diff --git a/src/services/Integrator/schemas/list-nft-order-response-schema.ts b/src/services/Integrator/schemas/list-nft-order-response-schema.ts new file mode 100644 index 0000000..4747ffd --- /dev/null +++ b/src/services/Integrator/schemas/list-nft-order-response-schema.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; +import poolSchema from './pool-schema.js'; +import infoSchema from './info-schema.js'; + +const listNFTOrderResponseSchema = z.object({ + result: z.array(poolSchema), + info: infoSchema, +}); + +export default listNFTOrderResponseSchema; diff --git a/src/services/Integrator/schemas/list-pool-response-schema.ts b/src/services/Integrator/schemas/list-pool-response-schema.ts new file mode 100644 index 0000000..2e19738 --- /dev/null +++ b/src/services/Integrator/schemas/list-pool-response-schema.ts @@ -0,0 +1,26 @@ +import { z } from 'zod'; +import { evmAddressSchema } from './util-schemas.js'; +import basicPoolInfo from './basic-pool-info-schema.js'; +import infoSchema from './info-schema.js'; + +const poolOfListPoolSchema = z.object({ + token0: z.string().nonempty(), + token1: z.string().nonempty(), + token0Address: evmAddressSchema, + token1Address: evmAddressSchema, + + token0Decimals: z.number().int().nonnegative().max(18), + token1Decimals: z.number().int().nonnegative().max(18), + WETH9: evmAddressSchema, + + ...basicPoolInfo.shape, + + type: z.string().nonempty(), +}); + +const listPoolResponseSchema = z.object({ + result: z.array(poolOfListPoolSchema), + info: infoSchema, +}); + +export default listPoolResponseSchema; diff --git a/src/services/Integrator/schemas/pool-schema.ts b/src/services/Integrator/schemas/pool-schema.ts new file mode 100644 index 0000000..3053734 --- /dev/null +++ b/src/services/Integrator/schemas/pool-schema.ts @@ -0,0 +1,33 @@ +import { z } from 'zod'; +import { evmAddressSchema } from './util-schemas.js'; + +const poolSchema = z.object({ + tokenId: evmAddressSchema, + + token0: z.string().nonempty(), + token1: z.string().nonempty(), + token0Address: evmAddressSchema, + token1Address: evmAddressSchema, + token0Decimals: z.number().int().nonnegative().max(18), + token1Decimals: z.number().int().nonnegative().max(18), + + amount: z.number().nonnegative(), + amount0: z.number().nonnegative(), + amount1: z.number().nonnegative(), + from: z.number().nonnegative(), + to: z.number().nonnegative(), + fee: z.number().nonnegative(), + collectFee: z.number().nonnegative(), + reward: z.number().nonnegative(), + apr: z.number().nonnegative(), + boost: z.number().int().nonnegative(), + isStaked: z.boolean(), + poolFee: z.number().nonnegative(), + poolAddress: evmAddressSchema, + veOrnForMaxBoost: z.number().nonnegative(), + veOrnMaxBoost: z.number().nonnegative(), + veORNCurrent: z.number().nonnegative(), + time: z.number().int().nonnegative(), // tim +}); + +export default poolSchema; diff --git a/src/services/Integrator/schemas/test-incrementor-schema.ts b/src/services/Integrator/schemas/test-incrementor-schema.ts new file mode 100644 index 0000000..945d461 --- /dev/null +++ b/src/services/Integrator/schemas/test-incrementor-schema.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; +import infoSchema from './info-schema.js'; + +const testIncrementorSchema = z.object({ + result: z.number().int(), + info: infoSchema, +}); + +export default testIncrementorSchema; diff --git a/src/services/Integrator/schemas/util-schemas.ts b/src/services/Integrator/schemas/util-schemas.ts new file mode 100644 index 0000000..f0e80b2 --- /dev/null +++ b/src/services/Integrator/schemas/util-schemas.ts @@ -0,0 +1,14 @@ +import { ethers } from 'ethers'; +import { z } from 'zod'; + +export const evmAddressSchema = z + .string() + .refine(ethers.utils.isAddress, (v) => ({ + message: `${v} is not a valid address`, + })); + +export const hexStringSchema = z + .string() + .refine(ethers.utils.isHexString, (v) => ({ + message: `${v} is not a valid hex string`, + })); diff --git a/src/services/Integrator/schemas/veORN-info-schema.ts b/src/services/Integrator/schemas/veORN-info-schema.ts new file mode 100644 index 0000000..1e05026 --- /dev/null +++ b/src/services/Integrator/schemas/veORN-info-schema.ts @@ -0,0 +1,26 @@ +import { z } from 'zod'; +import { evmAddressSchema } from './util-schemas.js'; +import infoSchema from './info-schema.js'; + +const veORNResultSchema = z.object({ + avgAPR: z.number(), + minAPR: z.number(), + maxAPR: z.number(), + veTokenAddress: evmAddressSchema, + totalORNLocked: z.number(), + totalVeORN: z.number(), + weeklyReward: z.number(), + userAPR: z.number(), + userVeORN: z.number(), + userORNLocked: z.number(), + userLockEndDate: z.number(), + userReward: z.number(), + userWeeklyReward: z.number() +}); + +const veORNInfoSchema = z.object({ + result: veORNResultSchema, + info: infoSchema, +}); + +export default veORNInfoSchema; diff --git a/src/services/Integrator/schemas/voting-info-schema.ts b/src/services/Integrator/schemas/voting-info-schema.ts new file mode 100644 index 0000000..bb0718f --- /dev/null +++ b/src/services/Integrator/schemas/voting-info-schema.ts @@ -0,0 +1,27 @@ +import { z } from 'zod'; +import infoSchema from './info-schema.js'; + +const poolSchema = z.object({ + allVote: z.number(), + name: z.string(), + poolAddress: z.string(), + type: z.string(), + userVote: z.number() +}) + +const votingResultSchema = z.object({ + absoluteVeTokenInVoting: z.number(), + pools: z.array(poolSchema), + userVeTokenBalance: z.number(), + userVeTokenInVoting: z.number(), + veTokenAddress: z.string(), + votingAddress: z.string(), + weeklyReward: z.number() +}) + +const votingInfoSchema = z.object({ + result: votingResultSchema, + info: infoSchema, +}); + +export default votingInfoSchema; diff --git a/src/types.ts b/src/types.ts index 64449e8..88d32ac 100644 --- a/src/types.ts +++ b/src/types.ts @@ -252,6 +252,12 @@ export type VerboseUnitConfig = { // http://10.23.5.11:3003/, // https://price-feed:3003/ } + integrator: { + api: string + // For example: + // http://localhost:3004/, + // http:// + } } basicAuth?: BasicAuthCredentials }