Merge remote-tracking branch 'origin/main' into op-4438/pf-cex-prices

This commit is contained in:
Kirill Litvinov
2024-03-07 16:12:21 +03:00
102 changed files with 11453 additions and 1715 deletions

View File

@@ -8,7 +8,7 @@ import errorSchema from './schemas/errorSchema.js';
import placeAtomicSwapSchema from './schemas/placeAtomicSwapSchema.js';
import { AggregatorWS } from './ws/index.js';
import { atomicSwapHistorySchema } from './schemas/atomicSwapHistorySchema.js';
import type { BasicAuthCredentials, SignedCancelOrderRequest, SignedOrder } from '../../types.js';
import type { BasicAuthCredentials, OrderSource, SignedCancelOrderRequest, SignedOrder } from '../../types.js';
import {
pairConfigSchema, aggregatedOrderbookSchema,
exchangeOrderbookSchema, poolReservesSchema,
@@ -74,13 +74,13 @@ class Aggregator {
}
getOrder = (orderId: string, owner?: string) => {
if (!ethers.utils.isHexString(orderId)) {
if (!ethers.isHexString(orderId)) {
throw new Error(`Invalid order id: ${orderId}. Must be a hex string`);
}
const url = new URL(`${this.apiUrl}/api/v1/order`);
url.searchParams.append('orderId', orderId);
if (owner !== undefined) {
if (!ethers.utils.isAddress(owner)) {
if (!ethers.isAddress(owner)) {
throw new Error(`Invalid owner address: ${owner}`);
}
url.searchParams.append('owner', owner);
@@ -196,7 +196,8 @@ class Aggregator {
isCreateInternalOrder: boolean,
isReversedOrder?: boolean,
partnerId?: string,
fromWidget?: boolean,
source?: OrderSource,
rawExchangeRestrictions?: string | undefined,
) => {
const headers = {
'Content-Type': 'application/json',
@@ -205,7 +206,7 @@ class Aggregator {
'X-Reverse-Order': isReversedOrder ? 'true' : 'false',
},
...(partnerId !== undefined) && { 'X-Partner-Id': partnerId },
...(fromWidget !== undefined) && { 'X-From-Widget': fromWidget ? 'true' : 'false' },
...(source !== undefined) && { 'X-Source': source },
...this.basicAuthHeaders,
};
@@ -226,7 +227,7 @@ class Aggregator {
{
headers,
method: 'POST',
body: JSON.stringify(signedOrder),
body: JSON.stringify({ ...signedOrder, rawExchangeRestrictions }),
},
errorSchema,
);

View File

@@ -3,22 +3,22 @@ import { z } from 'zod';
import { exchanges, orderStatuses, subOrderStatuses } from '../../../constants/index.js';
const blockchainOrderSchema = z.object({
id: z.string().refine(ethers.utils.isHexString, (value) => ({
id: z.string().refine(ethers.isHexString, (value) => ({
message: `blockchainOrder.id must be a hex string, got ${value}`,
})),
senderAddress: z.string().refine(ethers.utils.isAddress, (value) => ({
senderAddress: z.string().refine(ethers.isAddress, (value) => ({
message: `blockchainOrder.senderAddress must be an address, got ${value}`,
})),
matcherAddress: z.string().refine(ethers.utils.isAddress, (value) => ({
matcherAddress: z.string().refine(ethers.isAddress, (value) => ({
message: `blockchainOrder.matcherAddress must be an address, got ${value}`,
})),
baseAsset: z.string().refine(ethers.utils.isAddress, (value) => ({
baseAsset: z.string().refine(ethers.isAddress, (value) => ({
message: `blockchainOrder.baseAsset must be an address, got ${value}`,
})),
quoteAsset: z.string().refine(ethers.utils.isAddress, (value) => ({
quoteAsset: z.string().refine(ethers.isAddress, (value) => ({
message: `blockchainOrder.quoteAsset must be an address, got ${value}`,
})),
matcherFeeAsset: z.string().refine(ethers.utils.isAddress, (value) => ({
matcherFeeAsset: z.string().refine(ethers.isAddress, (value) => ({
message: `blockchainOrder.matcherFeeAsset must be an address, got ${value}`,
})),
amount: z.number().int().nonnegative(),
@@ -27,7 +27,7 @@ const blockchainOrderSchema = z.object({
nonce: z.number(),
expiration: z.number(),
buySide: z.union([z.literal(1), z.literal(0)]),
signature: z.string().refine(ethers.utils.isHexString, (value) => ({
signature: z.string().refine(ethers.isHexString, (value) => ({
message: `blockchainOrder.signature must be a hex string, got ${value}`,
})).nullable(),
isPersonalSign: z.boolean(),
@@ -43,8 +43,6 @@ const tradeInfoSchema = z.object({
updateTime: z.number(),
matchedBlockchainOrder: blockchainOrderSchema.optional(),
matchedSubOrderId: z.number().int().nonnegative().optional(),
exchangeTradeInfo: z.boolean(),
poolTradeInfo: z.boolean(),
});
const baseOrderSchema = z.object({
@@ -53,7 +51,7 @@ const baseOrderSchema = z.object({
amount: z.number().nonnegative(),
remainingAmount: z.number().nonnegative(),
price: z.number().nonnegative(),
sender: z.string().refine(ethers.utils.isAddress, (value) => ({
sender: z.string().refine(ethers.isAddress, (value) => ({
message: `order.sender must be an address, got ${value}`,
})),
filledAmount: z.number().nonnegative(),
@@ -77,16 +75,17 @@ const brokerAddressSchema = z.enum([
'SELF_BROKER'
])
.or(selfBrokerSchema)
.or(z.string().refine(ethers.utils.isAddress, (value) => ({
.or(z.string().refine(ethers.isAddress, (value) => ({
message: `subOrder.subOrders.[n].brokerAddress must be an address, got ${value}`,
})));
const subOrderSchema = baseOrderSchema.extend({
price: z.number(),
id: z.number(),
parentOrderId: z.string().refine(ethers.utils.isHexString, (value) => ({
parentOrderId: z.string().refine(ethers.isHexString, (value) => ({
message: `subOrder.parentOrderId must be a hex string, got ${value}`,
})),
exchange: z.string(),
exchanges: z.string().array().optional(),
brokerAddress: brokerAddressSchema,
tradesInfo: z.record(
z.string().uuid(),
@@ -97,11 +96,11 @@ const subOrderSchema = baseOrderSchema.extend({
});
const orderSchema = z.object({
orderId: z.string().refine(ethers.utils.isHexString, (value) => ({
orderId: z.string().refine(ethers.isHexString, (value) => ({
message: `orderId must be a hex string, got ${value}`,
})),
order: baseOrderSchema.extend({
id: z.string().refine(ethers.utils.isHexString, (value) => ({
id: z.string().refine(ethers.isHexString, (value) => ({
message: `order.id must be a hex string, got ${value}`,
})),
fee: z.number().nonnegative(),

View File

@@ -7,6 +7,13 @@ const orderInfoSchema = z.object({
safePrice: z.number(),
}).nullable();
const exchangeContractStep = z.object({
pool: z.string(),
assetIn: z.string(),
assetOut: z.string(),
factory: z.string(),
});
const swapInfoBase = z.object({
id: z.string(),
amountIn: z.number(),
@@ -22,12 +29,7 @@ const swapInfoBase = z.object({
minAmountOut: z.number(),
minAmountIn: z.number(),
marketPrice: z.number().nullable(), // spending asset market price
exchangeContractPath: z.array(z.object({
pool: z.string(),
assetIn: z.string(),
assetOut: z.string(),
factory: z.string(),
})),
exchangeContractPath: z.array(exchangeContractStep),
alternatives: z.object({ // execution alternatives
exchanges: z.array(z.string()),
path: z.array(z.string()),
@@ -40,6 +42,13 @@ const swapInfoBase = z.object({
isThroughPoolOrCurve: z.boolean(),
}).array(),
assetNameMapping: z.record(z.string()).optional(), // address to ERC20 names
usd: z.object({ // USD info of this swap, nullable
aa: z.number().optional(), // available amount in, USD
aao: z.number().optional(), // available amount out, USD
mo: z.number().optional(), // market amount out, USD
mi: z.number().optional(), // market amount in, USD
d: z.string().optional(), // difference in available amount in/out (USD) and market amount out/in (USD) in percentage
}).optional(),
});
const swapInfoByAmountIn = swapInfoBase.extend({

View File

@@ -17,8 +17,6 @@ import unsubscriptionDoneSchema from './schemas/unsubscriptionDoneSchema.js';
import assetPairConfigSchema from './schemas/assetPairConfigSchema.js';
import type { fullOrderSchema, orderUpdateSchema } from './schemas/addressUpdateSchema.js';
import { objectKeys } from '../../../utils/objectKeys.js';
// import assertError from '../../../utils/assertError.js';
// import errorSchema from './schemas/errorSchema';
const UNSUBSCRIBE = 'u';
const SERVER_PING_INTERVAL = 30000;
@@ -42,7 +40,7 @@ type SwapInfoSubscriptionPayload = {
i: string // asset in
o: string // asset out
a: number // amount IN/OUT
es?: string[] | 'cex' | 'pools' // exchange list of all cex or all pools (ORION_POOL, UNISWAP, PANCAKESWAP etc)
es?: string // exchange list of all cex or all pools (ORION_POOL, UNISWAP, PANCAKESWAP etc)
e?: boolean // is amount IN? Value `false` means a = amount OUT, `true` if omitted
is?: boolean // instant settlement
}
@@ -528,6 +526,13 @@ class AggregatorWS {
availableAmountOut: item.aao,
})),
assetsNameMapping: json.anm,
usdInfo: json.usd && {
availableAmountIn: json.usd.aa,
availableAmountOut: json.usd.aao,
marketAmountOut: json.usd.mo,
marketAmountIn: json.usd.mi,
difference: json.usd.d,
},
};
switch (json.k) { // kind

View File

@@ -23,6 +23,7 @@ const subOrderSchema = z.object({
A: z.number(), // settled amount
p: z.number(), // avg weighed settlement price
e: z.string(), // exchange
es: z.string().array().optional(), // exchanges
b: z.string(), // broker address
S: z.enum(subOrderStatuses), // status
o: z.boolean(), // internal only
@@ -52,6 +53,7 @@ export const orderUpdateSchema = z.object({
subOrders: o.c.map((so) => ({
pair: so.P,
exchange: so.e,
exchanges: so.es,
id: so.i,
amount: so.a,
settledAmount: so.A,
@@ -106,6 +108,7 @@ export const fullOrderSchema = z.object({
subOrders: o.c.map((so) => ({
pair: so.P,
exchange: so.e,
exchanges: so.es,
id: so.i,
amount: so.a,
settledAmount: so.A,

View File

@@ -1,6 +1,7 @@
import { z } from 'zod';
import MessageType from '../MessageType.js';
import baseMessageSchema from './baseMessageSchema.js';
import factories from '../../../../constants/factories.js';
const alternativeSchema = z.object({ // execution alternatives
e: z.string().array(), // exchanges
@@ -11,6 +12,7 @@ const alternativeSchema = z.object({ // execution alternatives
aa: z.number().optional(), // available amount in
aao: z.number().optional(), // available amount out
});
const factorySchema = z.enum(factories);
const swapInfoSchemaBase = baseMessageSchema.extend({
T: z.literal(MessageType.SWAP_INFO),
S: z.string(), // swap request id
@@ -37,8 +39,15 @@ const swapInfoSchemaBase = baseMessageSchema.extend({
p: z.string(), // pool address
ai: z.string().toUpperCase(), // asset in
ao: z.string().toUpperCase(), // asset out
f: z.string().toUpperCase(), // factory
}))
f: factorySchema, // factory
})),
usd: z.object({ // USD info of this swap, nullable
aa: z.number().optional(), // available amount in, USD
aao: z.number().optional(), // available amount out, USD
mo: z.number().optional(), // market amount out, USD
mi: z.number().optional(), // market amount in, USD
d: z.string().optional(), // difference in available amount in/out (USD) and market amount out/in (USD) in percentage
}).optional(),
});
const swapInfoSchemaByAmountIn = swapInfoSchemaBase.extend({

View File

@@ -10,15 +10,12 @@ import {
userEarnedSchema,
type PairStatusEnum,
pairStatusSchema,
governanceContractsSchema,
governancePoolsSchema,
governancePoolSchema,
governanceChainsInfoSchema,
pricesWithQuoteAssetSchema,
referralDataSchema,
} from './schemas/index.js';
import type redeemOrderSchema from '../Aggregator/schemas/redeemOrderSchema.js';
import { sourceAtomicHistorySchema, targetAtomicHistorySchema } from './schemas/atomicHistorySchema.js';
import { makePartial } from '../../utils/index.js';
import { makePartial } from '../../utils';
import type { networkCodes } from '../../constants/index.js';
import { fetchWithValidation } from 'simple-typed-fetch';
import type { BasicAuthCredentials } from '../../types.js';
@@ -59,6 +56,14 @@ type AtomicSwapHistoryTargetQuery = AtomicSwapHistoryBaseQuery & {
expiredRedeem?: 0 | 1
state?: 'REDEEMED' | 'BEFORE-REDEEM'
}
type PlatformFees = {
assetIn: string
assetOut: string
walletAddress?: string | undefined
fromWidget?: string | undefined
}
class BlockchainService {
private readonly apiUrl: string;
@@ -106,10 +111,7 @@ class BlockchainService {
this.getBlockNumber = this.getBlockNumber.bind(this);
this.getRedeemOrderBySecretHash = this.getRedeemOrderBySecretHash.bind(this);
this.claimOrder = this.claimOrder.bind(this);
this.getGovernanceContracts = this.getGovernanceContracts.bind(this);
this.getGovernancePools = this.getGovernancePools.bind(this);
this.getGovernancePool = this.getGovernancePool.bind(this);
this.getGovernanceChainsInfo = this.getGovernanceChainsInfo.bind(this);
this.getGasLimits = this.getGasLimits.bind(this);
}
get basicAuthHeaders() {
@@ -223,31 +225,25 @@ class BlockchainService {
);
/**
* @deprecated In favor of getPlatformFees
*/
* @deprecated In favor of getPlatformFees
*/
getTokensFee = () => fetchWithValidation(
`${this.apiUrl}/api/tokensFee`,
z.record(z.string()).transform(makePartial),
{ headers: this.basicAuthHeaders }
);
getPlatformFees = (
{ assetIn, assetOut, walletAddress, fromWidget }: {
assetIn?: string | undefined,
assetOut?: string | undefined,
walletAddress?: string | undefined,
fromWidget?: string | undefined
}
getPlatformFees = ({
assetIn,
assetOut,
walletAddress,
fromWidget
}: PlatformFees
) => {
const url = new URL(`${this.apiUrl}/api/platform-fees`);
if (assetIn !== undefined) {
url.searchParams.append('assetIn', assetIn);
}
if (assetOut !== undefined) {
url.searchParams.append('assetOut', assetOut);
}
url.searchParams.append('assetIn', assetIn);
url.searchParams.append('assetOut', assetOut);
if (walletAddress !== undefined) {
url.searchParams.append('walletAddress', walletAddress);
@@ -264,6 +260,12 @@ class BlockchainService {
)
};
getReferralData = (walletAddress: string) => fetchWithValidation(
`${this.apiUrl}/api/referral-data/${walletAddress}`,
referralDataSchema,
{ headers: this.basicAuthHeaders }
);
getGasPriceWei = () => fetchWithValidation(
`${this.apiUrl}/api/gasPrice`,
z.string(),
@@ -427,9 +429,9 @@ class BlockchainService {
);
/**
* Sender is user address in source BlockchainService instance \
* Receiver is user address in target BlockchainService instance
*/
* Sender is user address in source BlockchainService instance \
* Receiver is user address in target BlockchainService instance
*/
getAtomicSwapHistory = (query: AtomicSwapHistorySourceQuery | AtomicSwapHistoryTargetQuery) => {
const url = new URL(`${this.apiUrl}/api/atomic/history/`);
@@ -484,28 +486,10 @@ class BlockchainService {
},
);
getGovernanceContracts = () => fetchWithValidation(
`${this.apiUrl}/api/governance/info`,
governanceContractsSchema,
{ headers: this.basicAuthHeaders },
);
getGovernancePools = () => fetchWithValidation(
`${this.apiUrl}/api/governance/pools`,
governancePoolsSchema,
{ headers: this.basicAuthHeaders },
);
getGovernancePool = (address: string) => fetchWithValidation(
`${this.apiUrl}/api/governance/pools/${address}`,
governancePoolSchema,
{ headers: this.basicAuthHeaders },
);
getGovernanceChainsInfo = () => fetchWithValidation(
`${this.apiUrl}/api/governance/chains-info`,
governanceChainsInfoSchema,
{ headers: this.basicAuthHeaders },
getGasLimits = () => fetchWithValidation(
`${this.apiUrl}/api/baseLimits`,
z.record(z.number()),
{ headers: this.basicAuthHeaders }
);
}

View File

@@ -16,9 +16,9 @@ const baseAtomicHistoryItem = z.object({
_id: z.string(),
__v: z.number(),
asset: z.string(),
sender: z.string().refine(ethers.utils.isAddress),
secretHash: z.string().refine(ethers.utils.isHexString),
receiver: z.string().refine(ethers.utils.isAddress).optional(),
sender: z.string().refine(ethers.isAddress),
secretHash: z.string().refine(ethers.isHexString),
receiver: z.string().refine(ethers.isAddress).optional(),
secret: z.string().optional(),
});

View File

@@ -1,7 +0,0 @@
import { z } from 'zod';
const governanceChainsInfoSchema = z.object({
isChainSupported: z.boolean(),
});
export default governanceChainsInfoSchema;

View File

@@ -1,19 +0,0 @@
import { z } from 'zod';
const governanceContractsSchema = z.object({
controllerAddress: z.string(),
veTOKENAddress: z.string(),
veTOKENYieldDistributorV4Address: z.string(),
time_total: z.string(),
absolute_ve_token_in_voting: z.string(),
info: z.record(
z.string(),
z.object({
gaugeAddress: z.string(),
gaugeType: z.number(),
gaugeName: z.string(),
})
),
});
export default governanceContractsSchema;

View File

@@ -1,18 +0,0 @@
import { z } from 'zod';
const governancePoolSchema = z.object({
min_apr: z.string(),
max_apr: z.string(),
tvl: z.string(),
lp_supply: z.string(),
lp_staked: z.string(),
lp_staked_with_boost: z.string(),
lp_price_in_usd: z.string(),
reward_per_period: z.string(),
lock_time_for_max_multiplier: z.string(),
lock_max_multiplier: z.string(),
veorn_max_multiplier: z.string(),
veorn_boost_scale_factor: z.string(),
});
export default governancePoolSchema;

View File

@@ -1,28 +0,0 @@
import { z } from 'zod';
const governancePoolsSchema = z.array(
z.object({
slug: z.string(),
identifier: z.string(),
chain: z.string(),
platform: z.string(),
logo: z.string(),
pair: z.string(),
lp_address: z.string(),
lp_staked: z.string(),
lp_staked_with_boost: z.string(),
lp_supply: z.string(),
lp_price_in_usd: z.string(),
farm_address: z.string(),
pool_tokens: z.tuple([z.string(), z.string()]),
pool_rewards: z.array(z.string()),
tvl: z.string(),
min_apr: z.string(),
max_apr: z.string(),
reward_per_period: z.array(z.string()),
weight: z.string(),
liquidity: z.string(),
})
);
export default governancePoolsSchema;

View File

@@ -12,9 +12,6 @@ export { default as atomicSummarySchema } from './atomicSummarySchema.js';
export { default as poolsLpAndStakedSchema } from './poolsLpAndStakedSchema.js';
export { default as userVotesSchema } from './userVotesSchema.js';
export { default as userEarnedSchema } from './userEarnedSchema.js';
export { default as governanceContractsSchema } from './governanceContractsSchema.js';
export { default as governancePoolsSchema } from './governancePoolsSchema.js';
export { default as governancePoolSchema } from './governancePoolSchema.js';
export { default as governanceChainsInfoSchema } from './governanceChainsInfoSchema.js';
export { default as poolsV3InfoSchema } from './poolsV3InfoSchema.js';
export { pricesWithQuoteAssetSchema } from './pricesWithQuoteAssetSchema.js';
export { referralDataSchema } from './referralDataSchema.js';

View File

@@ -11,7 +11,7 @@ const infoSchema = z.object({
chainId: z.number(),
chainName: z.string(),
exchangeContractAddress: z.string(),
swapExecutorContractAddress: z.string().optional(),
swapExecutorContractAddress: z.string(),
oracleContractAddress: z.string(),
matcherAddress: z.string(),
orderFeePercent: z.number(),

View File

@@ -0,0 +1,6 @@
import { z } from 'zod';
export const referralDataSchema = z.object({
referer: z.string().nullable(),
isReferral: z.boolean(),
});

View File

@@ -0,0 +1 @@
export const LOCK_START_TIME = 1690848000;// Aug 01 2023 00:00:00 UTC

View File

@@ -0,0 +1,266 @@
import {
environmentResponseSchema,
getPoolResponseSchema,
listAmountResponseSchema,
listNFTOrderResponseSchema,
listPoolResponseSchema,
listPoolV2ResponseSchema,
listPoolV3ResponseSchema,
PoolV2InfoResponseSchema,
testIncrementorSchema,
veORNInfoResponseSchema,
votingInfoResponseSchema
} from './schemas';
import { fetchWithValidation } from 'simple-typed-fetch';
import { BigNumber } from 'bignumber.js';
import { WEEK_DAYS, YEAR } from '../../constants';
import { LOCK_START_TIME } from './constants';
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' | 'OrionV2Factory'
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 IndexerService {
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.getListPool = this.getListPool.bind(this);
this.listPoolV2 = this.listPoolV2.bind(this);
this.poolV2Info = this.poolV2Info.bind(this);
this.listPoolV3 = this.listPoolV3.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<Payload, 'chainId' | 'jsonrpc'>) => {
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 getAmountByORN = (amountToken: string, lockingDays: number) => {
const alpha = 730 / (30 - Math.sqrt(730 / 7)) ** (1 / 3);
const deltaDaysBN = BigNumber(lockingDays);
if (deltaDaysBN.lte(0)) return BigNumber(0);
const multSQRT = deltaDaysBN.dividedBy(WEEK_DAYS).sqrt();
const multCUBE = deltaDaysBN.dividedBy(alpha).pow(3);
return BigNumber(amountToken)
.multipliedBy(multSQRT.plus(multCUBE));
};
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 getListPool = (userAddress?: string) => {
return fetchWithValidation(this.apiUrl, listPoolResponseSchema, {
method: 'POST',
body: this.makeRPCPayload({
model: 'OrionVoting',
method: 'listPool',
params: [userAddress],
}),
});
};
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 listPoolV2 = (address?: string) => {
return fetchWithValidation(this.apiUrl, listPoolV2ResponseSchema, {
method: 'POST',
body: this.makeRPCPayload({
model: 'OrionFarmV2',
method: 'listPool',
params: [address],
}),
});
};
readonly poolV2Info = (token0: string, token1: string, address: string | undefined) => {
return fetchWithValidation(this.apiUrl, PoolV2InfoResponseSchema, {
method: 'POST',
body: this.makeRPCPayload({
model: 'OrionV2Factory',
method: 'getPoolInfo',
params: [token0, token1, address],
}),
});
};
readonly listPoolV3 = (address?: string) => {
return fetchWithValidation(this.apiUrl, listPoolV3ResponseSchema, {
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();
};
}
export * as schemas from './schemas/index.js';
export { IndexerService };

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,23 @@
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(),
ORN: evmAddressSchema,
WETH9: evmAddressSchema,
OrionV3Factory: evmAddressSchema.optional(),
OrionV2Factory: evmAddressSchema.optional(),
OrionV3NFTManager: evmAddressSchema.optional(),
SwapRouterV3: evmAddressSchema.optional(),
OrionFarmV3: evmAddressSchema.optional(),
OrionFarmV2: evmAddressSchema.optional(),
OrionVoting: evmAddressSchema.optional(),
veORN: evmAddressSchema.optional(),
}),
info: infoSchema,
});
export default environmentResponseSchema;

View File

@@ -0,0 +1,20 @@
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 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.number(), basicPoolInfo.nullable()),
}),
info: infoSchema,
});
export default getPoolResponseSchema;

View File

@@ -0,0 +1,11 @@
export { default as environmentResponseSchema } from './environment-response-schema';
export { default as listNFTOrderResponseSchema } from './list-nft-order-response-schema';
export { default as getPoolResponseSchema } from './get-pool-response-schema';
export { default as listPoolResponseSchema } from './list-pool-schema';
export { default as listPoolV2ResponseSchema } from './list-pool-v2-response-schema';
export { default as PoolV2InfoResponseSchema } from './pool-v2-info-schema';
export { default as listPoolV3ResponseSchema } from './list-pool-v3-response-schema';
export { default as veORNInfoResponseSchema } from './veORN-info-schema';
export { default as listAmountResponseSchema } from './list-amount-schema';
export { default as votingInfoResponseSchema } from './voting-info-schema';
export { default as testIncrementorSchema } from './test-incrementor-schema';

View File

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

View File

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

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,11 @@
import { z } from 'zod';
import infoSchema from './info-schema';
import { listPoolV2Schema } from './list-pool-v2-response-schema';
import { listPoolV3Schema } from './list-pool-v3-response-schema';
const listPoolResponseSchema = z.object({
result: z.array(listPoolV2Schema.or(listPoolV3Schema)),
info: infoSchema,
});
export default listPoolResponseSchema;

View File

@@ -0,0 +1,62 @@
import { z } from 'zod';
import { evmAddressSchema } from './util-schemas.js';
import basicPoolInfo from './basic-pool-info-schema.js';
import infoSchema from './info-schema.js';
export const listPoolV2Schema = z.object({
pair: z.string(),
token0: z.string().nonempty(),
token1: z.string().nonempty(),
name: z.string(),
name0: z.string(),
name1: z.string(),
token0Address: evmAddressSchema,
token1Address: evmAddressSchema,
token0Decimals: z.number().int().nonnegative().max(18),
token1Decimals: z.number().int().nonnegative().max(18),
WETH9: evmAddressSchema,
farmAddress: z.string().optional(),
weight: z.number(),
liquidity0: z.number(),
liquidity1: z.number(),
token0Price: z.number(),
token1Price: z.number(),
totalLPSupply: z.number(),
totalLPStake: z.number(),
totalLPStakeInUSD: z.number(),
userLPStaked: z.number(),
userLPStakedInUSD: z.number(),
lpPriceInUSD: z.number(),
lpPriceInORN: z.number(),
userReward: z.number(),
weeklyReward: z.number(),
userAPR: z.number(),
lockMaxMultiplier: z.number(),
veornMaxMultiplier: z.number(),
veornBoostScaleFactor: z.number(),
lockTimeForMaxMultiplier: z.number(),
userBoost: z.number(),
userTimeDeposit: z.number(),
userLockTimeStart: z.number(),
userLockTimePeriod: z.number(),
userVeORN: z.number(),
userORN: z.number(),
userRewardToPool: z.number(),
boostTotalVeORN: z.number(),
boostCurrentPoolReward: z.number(),
boostTotalLiquidity: z.number(),
boostCurrentLiquidity: z.number(),
boostCurrentVeORN: z.number(),
boostTotalReward: z.number(),
...basicPoolInfo.shape,
type: z.string().nonempty(),
});
const listPoolV2ResponseSchema = z.object({
result: z.array(listPoolV2Schema),
info: infoSchema,
});
export default listPoolV2ResponseSchema;

View File

@@ -0,0 +1,32 @@
import { z } from 'zod';
import { evmAddressSchema } from './util-schemas.js';
import basicPoolInfo from './basic-pool-info-schema.js';
import infoSchema from './info-schema.js';
export const listPoolV3Schema = z.object({
token0: z.string().nonempty(),
token1: z.string().nonempty(),
name: z.string(),
name0: z.string(),
name1: z.string(),
token0Address: evmAddressSchema,
token1Address: evmAddressSchema,
token0Decimals: z.number().int().nonnegative().max(18),
token1Decimals: z.number().int().nonnegative().max(18),
WETH9: evmAddressSchema,
poolFee: z.number(),
weeklyReward: z.number(),
weight: z.number(),
totalLPStakeInUSD: z.number(),
...basicPoolInfo.shape,
type: z.literal('v3'),
});
const listPoolV3ResponseSchema = z.object({
result: z.array(listPoolV3Schema),
info: infoSchema,
});
export default listPoolV3ResponseSchema;

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,64 @@
import { z } from 'zod';
import { evmAddressSchema } from './util-schemas.js';
import basicPoolInfo from './basic-pool-info-schema';
import infoSchema from './info-schema.js';
const poolInfoSchema = z.object({
pair: z.string(),
name: z.string(),
token0: z.string(),
token1: z.string(),
name0: z.string(),
name1: z.string(),
token0Address: evmAddressSchema,
token1Address: evmAddressSchema,
token0Decimals: z.number().int().nonnegative().max(18),
token1Decimals: z.number().int().nonnegative().max(18),
WETH9: z.string(),
farmAddress: z.string().optional(),
weight: z.number(),
liquidity0: z.number(),
liquidity1: z.number(),
token0Price: z.number(),
token1Price: z.number(),
userLPBalance: z.number(),
userLPBalanceStr: z.string(),
totalLPSupply: z.number(),
totalLPStake: z.number(),
totalLPStakeInUSD: z.number(),
userLPStaked: z.number(),
userLPStakedInUSD: z.number(),
lpPriceInUSD: z.number(),
lpPriceInORN: z.number(),
userReward: z.number(),
userWeeklyReward: z.number(),
userRewardToPool: z.number(),
weeklyReward: z.number(),
userAPR: z.number(),
lockMaxMultiplier: z.number(),
veornMaxMultiplier: z.number(),
veornBoostScaleFactor: z.number(),
lockTimeForMaxMultiplier: z.number(),
userBoost: z.number(),
userTimeDeposit: z.number(),
userLockTimeStart: z.number(),
userLockTimePeriod: z.number(),
userVeORN: z.number(),
userORN: z.number(),
boostTotalVeORN: z.number(),
boostCurrentPoolReward: z.number(),
boostTotalLiquidity: z.number(),
boostCurrentLiquidity: z.number(),
boostCurrentVeORN: z.number(),
boostTotalReward: z.number(),
type: z.literal('v2'),
...basicPoolInfo.shape,
});
const PoolV2InfoResponseSchema = z.object({
result: poolInfoSchema,
info: infoSchema,
});
export default PoolV2InfoResponseSchema;

View File

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

View File

@@ -0,0 +1,14 @@
import { ethers } from 'ethers';
import { z } from 'zod';
export const evmAddressSchema = z
.string()
.refine(ethers.isAddress, (v) => ({
message: `${v} is not a valid address`,
}));
export const hexStringSchema = z
.string()
.refine(ethers.isHexString, (v) => ({
message: `${v} is not a valid hex string`,
}));

View File

@@ -0,0 +1,27 @@
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(),
userMinLockPeriod: z.number(),
});
const veORNInfoSchema = z.object({
result: veORNResultSchema,
info: infoSchema,
});
export default veORNInfoSchema;

View File

@@ -0,0 +1,34 @@
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(),
token0: z.string(), // deprecated
token1: z.string(), // deprecated
name0: z.string(),
name1: z.string(),
poolFee: z.number(),
userWeight: z.number(),
weight: 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;

View File

@@ -13,6 +13,7 @@ import {
aggregatedHistorySchema,
inviteCodeLinkSchema,
contractsAddressesSchema,
allTimeLeadersSchema,
} from './schemas/index.js';
import type { SupportedChainId } from '../../types.js';
@@ -69,8 +70,9 @@ class ReferralSystem {
this.getMiniStats = this.getMiniStats.bind(this);
this.getRewardsMapping = this.getRewardsMapping.bind(this);
this.claimRewards = this.claimRewards.bind(this);
this.getRating = this.getRating.bind(this);
this.getRating = this.getRating.bind(this);
this.getLeaderboard = this.getLeaderboard.bind(this);
this.getLeaderboardSingleChain = this.getLeaderboardSingleChain.bind(this);
this.getAllTimeLeaders = this.getAllTimeLeaders.bind(this);
this.getContractsAddresses = this.getContractsAddresses.bind(this);
this.getClaimInfo = this.getClaimInfo.bind(this);
this.getAggregatedHistory = this.getAggregatedHistory.bind(this);
@@ -205,7 +207,20 @@ class ReferralSystem {
errorSchema
);
getRating = (refererAddress: string | undefined, chainId: SupportedChainId) =>
getLeaderboard = (refererAddress: string | undefined) =>
fetchWithValidation(
`${this.apiUrl}/referer/ve/rating-table-leaderboard?tag=aggregated`,
ratingSchema,
{
headers:
refererAddress !== undefined
? { 'referer-address': refererAddress }
: {},
},
errorSchema
);
getLeaderboardSingleChain = (refererAddress: string | undefined, chainId: SupportedChainId) =>
fetchWithValidation(
`${this.apiUrl}/referer/ve/rating-table-leaderboard?chain_id=${chainId}`,
ratingSchema,
@@ -218,6 +233,19 @@ class ReferralSystem {
errorSchema
);
getAllTimeLeaders = (refererAddress: string | undefined) =>
fetchWithValidation(
`${this.apiUrl}/referer/ve/leaderboard-lifetime`,
allTimeLeadersSchema,
{
headers:
refererAddress !== undefined
? { 'referer-address': refererAddress }
: {},
},
errorSchema
);
getContractsAddresses = () =>
fetchWithValidation(
`${this.apiUrl}/referer/view/contracts`,

View File

@@ -0,0 +1,11 @@
import { z } from 'zod';
const allTimeLeadersSchema = z.array(z.object({
wallet: z.string(),
total_earnings_fmt: z.number(),
referrals_count_fmt: z.number(),
total_trades_fmt: z.number(),
weekly_earnings_fmt: z.number(),
}));
export default allTimeLeadersSchema;

View File

@@ -1,10 +1,10 @@
import { z } from 'zod';
import { SupportedChainId } from '../../../types.js';
import { isAddress } from 'ethers/lib/utils.js';
import { ethers } from 'ethers';
const contractsAddressesSchema = z.record(
z.nativeEnum(SupportedChainId),
z.string().refine(isAddress)
z.string().refine(ethers.isAddress)
);
export default contractsAddressesSchema;

View File

@@ -15,8 +15,16 @@ const distinctAnalyticsSchema = z.object({
latest_block: z.number(),
}),
),
total_earned: z.number(),
total_sent_to_governance: z.number(),
total_earned: z.number(),
total_volume: z.number(),
total_trades: z.number(),
all_time_earnings_boost_only: z.number(),
all_time_earnings_boost_only_usd: z.number(),
all_time_earnings: z.number(),
all_time_earnings_usd: z.number(),
all_weekly_earnings: z.number(),
all_weekly_earnings_usd: z.number(),
});
export default distinctAnalyticsSchema;

View File

@@ -10,3 +10,4 @@ export { default as claimInfoSchema } from './claimInfoSchema.js';
export { default as aggregatedHistorySchema } from './aggregatedHistorySchema.js';
export { default as contractsAddressesSchema } from './contractsAddressesSchema.js';
export { default as inviteCodeLinkSchema } from './inviteCodeLinkSchema.js';
export { default as allTimeLeadersSchema } from './allTimeLeadersSchema.js';

View File

@@ -1,8 +1,8 @@
import { z } from 'zod';
const linkSchema = z.object({
status: z.string(),
referer: z.string(),
ref_link: z.string(),
});
export default linkSchema;

View File

@@ -4,6 +4,9 @@ const ratingSchema = z.object({
info: z.object({
weekly_boost_budget: z.string(),
weekly_boost_budget_fmt: z.number(),
monthly_boost_budget: z.string(),
monthly_boost_budget_fmt: z.number(),
displayed_boost_budget_fmt: z.number(),
time_left_for_the_reward: z.number(),
time_left_for_the_reward_local: z.string(),
time_left_for_the_reward_utc: z.string(),
@@ -33,6 +36,11 @@ const ratingSchema = z.object({
weighted_volume_fmt: z.number(),
total_weight: z.string(),
total_weight_fmt: z.number(),
total_volume_fmt: z.number(),
weekly_earnings_fmt: z.number(),
total_earnings_fmt: z.number(),
referrals_count_fmt: z.number(),
total_trades_fmt: z.number(),
reward: z.string(),
reward_fmt: z.number()
})),

View File

@@ -2,3 +2,4 @@ export * as aggregator from './Aggregator/index.js';
export * as blockchainService from './BlockchainService/index.js';
export * as priceFeed from './PriceFeed/index.js';
export * as referralSystem from './ReferralSystem/index.js';
export * as indexer from './Indexer/index.js';