feat!: added Integrator service

This commit is contained in:
Alex Kraiz
2023-09-27 16:08:09 +04:00
parent dc58eeae9f
commit 65c21de2dd
16 changed files with 310 additions and 1 deletions

View File

@@ -58,6 +58,9 @@ export default class Orion {
priceFeed: { priceFeed: {
api: networkConfig.api + networkConfig.services.priceFeed.all, api: networkConfig.api + networkConfig.services.priceFeed.all,
}, },
integrator: {
api: networkConfig.api + networkConfig.services.integrator.http,
}
}, },
}; };
}) })

View File

@@ -7,6 +7,7 @@ import Exchange from './Exchange/index.js';
import FarmingManager from './FarmingManager/index.js'; import FarmingManager from './FarmingManager/index.js';
import { chains, envs } from '../config/index.js'; import { chains, envs } from '../config/index.js';
import type { networkCodes } from '../constants/index.js'; import type { networkCodes } from '../constants/index.js';
import { IntegratorService } from '../services/Integrator/index.js';
type KnownConfig = { type KnownConfig = {
env: KnownEnv env: KnownEnv
@@ -22,6 +23,8 @@ export default class Unit {
public readonly blockchainService: BlockchainService; public readonly blockchainService: BlockchainService;
public readonly integrator: IntegratorService;
public readonly aggregator: Aggregator; public readonly aggregator: Aggregator;
public readonly priceFeed: PriceFeed; public readonly priceFeed: PriceFeed;
@@ -58,6 +61,9 @@ export default class Unit {
priceFeed: { priceFeed: {
api: networkConfig.api + networkConfig.services.priceFeed.all, api: networkConfig.api + networkConfig.services.priceFeed.all,
}, },
integrator: {
api: networkConfig.api + networkConfig.services.integrator.http,
}
}, },
} }
} else { } else {
@@ -65,7 +71,7 @@ export default class Unit {
} }
const chainInfo = chains[config.chainId]; 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 = config.chainId; this.chainId = config.chainId;
this.networkCode = chainInfo.code; this.networkCode = chainInfo.code;
this.contracts = chainInfo.contracts this.contracts = chainInfo.contracts
@@ -75,6 +81,7 @@ export default class Unit {
this.provider.pollingInterval = 1000; 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.aggregator = new Aggregator(
this.config.services.aggregator.http, this.config.services.aggregator.http,
this.config.services.aggregator.ws, this.config.services.aggregator.ws,

View File

@@ -177,6 +177,9 @@ describe('Orion', () => {
priceFeed: { priceFeed: {
api: orionPriceFeedAPI + '/price-feed', api: orionPriceFeedAPI + '/price-feed',
}, },
integrator: {
api: '',
}
}, },
} }
} }

View File

@@ -14,6 +14,9 @@ export const pureEnvNetworksSchema = z.object({
priceFeed: z.object({ priceFeed: z.object({
all: z.string(), all: z.string(),
}), }),
integrator: z.object({
http: z.string(),
}),
}), }),
rpc: z.string().optional(), rpc: z.string().optional(),
liquidityMigratorAddress: z.string().optional(), liquidityMigratorAddress: z.string().optional(),

View File

@@ -0,0 +1 @@
export const AVAILABLE_POOL_FEE = ['0.01', '0.05', '0.3', '1'] as const;

View File

@@ -0,0 +1,121 @@
import {
environmentResponseSchema,
getPoolResponseSchema,
listNFTOrderResponseSchema,
listPoolResponseSchema,
} from './schemas/index.js';
import { fetchWithValidation } from 'simple-typed-fetch';
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 Payload =
| GetEnvironmentPayload
| ListNFTOrderPayload
| GetPoolInfoPayload
| ListPoolPayload;
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);
}
makeRPCPayload = (payload: Omit<Payload, 'chainId' | 'jsonrpc'>) => {
return JSON.stringify({
...payload,
chainId: this.chainId,
jsonrpc: '1.0',
});
};
private readonly getEnvironment = () => {
return fetchWithValidation(this.apiUrl, environmentResponseSchema, {
method: 'POST',
body: this.makeRPCPayload({
model: 'Environment',
method: 'getEnvironment',
params: [],
}),
});
};
private readonly listNFTOrder = (address: string) => {
return fetchWithValidation(this.apiUrl, listNFTOrderResponseSchema, {
method: 'POST',
body: this.makeRPCPayload({
model: 'OrionV3NFTManager',
method: 'listNFTOrder',
params: [address],
}),
});
};
private 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],
}),
});
}
private readonly listPool = (address: string) => {
return fetchWithValidation(this.apiUrl, listPoolResponseSchema, {
method: 'POST',
body: this.makeRPCPayload({
model: 'OrionFarmV3',
method: 'listPool',
params: [address],
}),
});
}
}
export * as schemas from './schemas/index.js';
export { IntegratorService };

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
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';

View File

@@ -0,0 +1,12 @@
import { z } from 'zod';
import { hexStringSchema } from './util-schemas.js';
const infoSchema = z.object({
blockNumber: z.number().int().nonnegative(),
blockHash: hexStringSchema,
timeRequest: z.number().int().nonnegative(),
timeAnswer: z.number().int().nonnegative(),
changes: z.number().int().nonnegative(),
});
export default infoSchema;

View File

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

View File

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

View File

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

View File

@@ -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.isAddress, (v) => ({
message: `${v} is not a valid hex string`,
}));

View File

@@ -252,6 +252,12 @@ export type VerboseUnitConfig = {
// http://10.23.5.11:3003/, // http://10.23.5.11:3003/,
// https://price-feed:3003/ // https://price-feed:3003/
} }
integrator: {
api: string
// For example:
// http://localhost:3004/,
// http://
}
} }
basicAuth?: BasicAuthCredentials basicAuth?: BasicAuthCredentials
} }