mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-04-02 02:57:59 +03:00
Merge branch 'refs/heads/main' into feat/OP-4308-cross-chain-swap
# Conflicts: # package-lock.json # package.json
This commit is contained in:
@@ -21,10 +21,15 @@ export default class Orion {
|
||||
|
||||
// TODO: get tradable pairs (aggregated)
|
||||
|
||||
public logger: ((message: string) => void) | undefined;
|
||||
|
||||
constructor(
|
||||
envOrConfig: KnownEnv | EnvConfig = 'production',
|
||||
overrides?: DeepPartial<EnvConfig>
|
||||
overrides?: DeepPartial<EnvConfig>,
|
||||
logger?: ((message: string) => void) | undefined
|
||||
) {
|
||||
this.logger = logger;
|
||||
|
||||
let config: EnvConfig;
|
||||
if (typeof envOrConfig === 'string') {
|
||||
const envConfig = envs[envOrConfig];
|
||||
@@ -33,7 +38,7 @@ export default class Orion {
|
||||
}
|
||||
this.env = envOrConfig;
|
||||
config = {
|
||||
analyticsAPI: envConfig.analyticsAPI,
|
||||
analyticsAPI: envConfig?.analyticsAPI,
|
||||
referralAPI: envConfig.referralAPI,
|
||||
networks: Object.entries(envConfig.networks).map(([chainId, networkConfig]) => {
|
||||
if (!isValidChainId(chainId)) throw new Error(`Invalid chainId: ${chainId}`);
|
||||
@@ -59,7 +64,7 @@ export default class Orion {
|
||||
api: networkConfig.api + networkConfig.services.priceFeed.all,
|
||||
},
|
||||
indexer: {
|
||||
api: networkConfig.api + networkConfig.services.indexer.http,
|
||||
api: networkConfig.api + networkConfig.services.indexer?.http,
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -92,7 +97,7 @@ export default class Orion {
|
||||
// api: networkConfig.api,
|
||||
nodeJsonRpc: networkConfig.nodeJsonRpc,
|
||||
services: networkConfig.services,
|
||||
});
|
||||
}, logger);
|
||||
return {
|
||||
...acc,
|
||||
[chainId]: unit,
|
||||
|
||||
@@ -397,7 +397,7 @@ async function shouldUseExchangeBalance(
|
||||
let useExchangeBalance = true;
|
||||
let additionalTransferAmount = 0n;
|
||||
|
||||
if (exchangeBalance == 0n) {
|
||||
if (walletBalance >= amount || exchangeBalance == 0n) {
|
||||
useExchangeBalance = false;
|
||||
additionalTransferAmount = amount;
|
||||
} else {
|
||||
|
||||
63
src/Unit/Pmm/abi/OrionRFQ.ts
Normal file
63
src/Unit/Pmm/abi/OrionRFQ.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
export const orionRFQContractABI =
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "info",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "makerAsset",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "takerAsset",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "maker",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "allowedSender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "makingAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "takingAmount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"internalType": "struct OrderRFQLib.OrderRFQ",
|
||||
"name": "order",
|
||||
"type": "tuple"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "signature",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "flagsAndAmount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "fillOrderRFQ",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
];
|
||||
84
src/Unit/Pmm/index.ts
Normal file
84
src/Unit/Pmm/index.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import type Unit from '../index';
|
||||
import { z } from 'zod';
|
||||
import {pmmOrderSchema} from "./schemas/order";
|
||||
import {simpleFetch} from "simple-typed-fetch";
|
||||
import {ethers, Wallet} from "ethers";
|
||||
import {BigNumber} from "bignumber.js";
|
||||
import { ERC20__factory } from '@orionprotocol/contracts/lib/ethers-v6/index.js';
|
||||
import {orionRFQContractABI} from "./abi/OrionRFQ";
|
||||
|
||||
export default class Pmm {
|
||||
private readonly unit: Unit;
|
||||
private readonly provider: ethers.Provider;
|
||||
private contractAddress: string;
|
||||
|
||||
constructor(unit: Unit) {
|
||||
this.unit = unit;
|
||||
this.provider = unit.provider;
|
||||
this.contractAddress = '';
|
||||
// this.contractAddress = '0x89357522c0ed6e557d39dc75290859246077bdfc';
|
||||
}
|
||||
|
||||
private isInitialized() : boolean {
|
||||
return this.contractAddress !== '';
|
||||
}
|
||||
|
||||
public async init() {
|
||||
if(this.isInitialized())
|
||||
return;
|
||||
const { orionPMMRouterContractAddress } = await simpleFetch(this.unit.blockchainService.getPmmInfo)();
|
||||
this.contractAddress = orionPMMRouterContractAddress;
|
||||
}
|
||||
|
||||
public async getContractAddress() {
|
||||
await this.init();
|
||||
return this.contractAddress;
|
||||
}
|
||||
|
||||
public async setAllowance(token: string, amount: string, signer: Wallet) {
|
||||
await this.init();
|
||||
|
||||
const bnTargetAmount = new BigNumber(amount);
|
||||
const walletAddress = await signer.getAddress();
|
||||
|
||||
const tokenContract = ERC20__factory
|
||||
.connect(token, this.unit.provider);
|
||||
|
||||
const unsignedApproveTx = await tokenContract
|
||||
.approve.populateTransaction(
|
||||
this.contractAddress,
|
||||
bnTargetAmount.toString()
|
||||
);
|
||||
const nonce = await this.provider.getTransactionCount(walletAddress, 'pending');
|
||||
const { gasPrice, maxFeePerGas } = await this.provider.getFeeData();
|
||||
const network = await this.provider.getNetwork();
|
||||
|
||||
if (gasPrice !== null)
|
||||
unsignedApproveTx.gasPrice = gasPrice;
|
||||
|
||||
if(maxFeePerGas !== null)
|
||||
unsignedApproveTx.maxFeePerGas = maxFeePerGas;
|
||||
|
||||
unsignedApproveTx.chainId = network.chainId;
|
||||
unsignedApproveTx.nonce = nonce;
|
||||
unsignedApproveTx.from = walletAddress;
|
||||
const gasLimit = await this.provider.estimateGas(unsignedApproveTx);
|
||||
unsignedApproveTx.gasLimit = gasLimit;
|
||||
|
||||
const signedTx = await signer.signTransaction(unsignedApproveTx);
|
||||
const txResponse = await this.provider.broadcastTransaction(signedTx);
|
||||
await txResponse.wait();
|
||||
}
|
||||
|
||||
public async fillRFQOrder(order : z.infer<typeof pmmOrderSchema>, signer: Wallet) {
|
||||
await this.init();
|
||||
|
||||
if(!order.success)
|
||||
throw Error("Invalid order provided");
|
||||
|
||||
const contract = new ethers.Contract(this.contractAddress, orionRFQContractABI, signer);
|
||||
|
||||
// @ts-ignore
|
||||
return contract.fillOrderRFQ(order.order, order.signature, BigInt(0));
|
||||
}
|
||||
}
|
||||
18
src/Unit/Pmm/schemas/order.ts
Normal file
18
src/Unit/Pmm/schemas/order.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import {z} from "zod";
|
||||
|
||||
export const pmmOrderQuotationSchema = z.object({
|
||||
info: z.string().default(''),
|
||||
makerAsset: z.string().default(''),
|
||||
takerAsset: z.string().default(''),
|
||||
maker: z.string().default(''),
|
||||
allowedSender: z.string().default(''),
|
||||
makingAmount: z.string().default(''),
|
||||
takingAmount: z.string().default(''),
|
||||
});
|
||||
|
||||
export const pmmOrderSchema = z.object({
|
||||
order: pmmOrderQuotationSchema.default({}),
|
||||
signature: z.string().default(''),
|
||||
success: z.boolean().default(false),
|
||||
error: z.string().default(''),
|
||||
});
|
||||
@@ -1,16 +1,17 @@
|
||||
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 { Aggregator } from '../services/Aggregator';
|
||||
import { BlockchainService } from '../services/BlockchainService';
|
||||
import { PriceFeed } from '../services/PriceFeed';
|
||||
import type {
|
||||
KnownEnv,
|
||||
SupportedChainId,
|
||||
VerboseUnitConfig,
|
||||
} from '../types.js';
|
||||
import Exchange from './Exchange/index.js';
|
||||
import { chains, envs } from '../config/index.js';
|
||||
import { chains, envs } from '../config';
|
||||
import type { networkCodes } from '../constants/index.js';
|
||||
import { IndexerService } from '../services/Indexer/index.js';
|
||||
import { IndexerService } from '../services/Indexer';
|
||||
import Pmm from "./Pmm";
|
||||
|
||||
type KnownConfig = {
|
||||
env: KnownEnv
|
||||
@@ -26,10 +27,12 @@ export default class Unit {
|
||||
|
||||
public readonly blockchainService: BlockchainService;
|
||||
|
||||
public readonly indexer: IndexerService;
|
||||
public readonly indexer: IndexerService | undefined;
|
||||
|
||||
public readonly aggregator: Aggregator;
|
||||
|
||||
public readonly pmm: Pmm;
|
||||
|
||||
public readonly priceFeed: PriceFeed;
|
||||
|
||||
public readonly exchange: Exchange;
|
||||
@@ -38,7 +41,10 @@ export default class Unit {
|
||||
|
||||
public readonly contracts: Record<string, string>;
|
||||
|
||||
constructor(config: KnownConfig | VerboseUnitConfig) {
|
||||
public logger: ((message: string) => void) | undefined;
|
||||
|
||||
constructor(config: KnownConfig | VerboseUnitConfig, logger?: ((message: string) => void) | undefined) {
|
||||
this.logger = logger;
|
||||
if ('env' in config) {
|
||||
const staticConfig = envs[config.env];
|
||||
if (!staticConfig) {
|
||||
@@ -83,7 +89,7 @@ export default class Unit {
|
||||
api: networkConfig.api + networkConfig.services.priceFeed.all,
|
||||
},
|
||||
indexer: {
|
||||
api: networkConfig.api + networkConfig.services.indexer.http,
|
||||
api: networkConfig.api + networkConfig.services.indexer?.http,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -106,19 +112,23 @@ export default class Unit {
|
||||
this.config.services.blockchainService.http,
|
||||
this.config.basicAuth
|
||||
);
|
||||
this.indexer = new IndexerService(
|
||||
this.config.services.indexer.api,
|
||||
intNetwork
|
||||
);
|
||||
this.indexer = this.config.services.indexer
|
||||
? new IndexerService(
|
||||
this.config.services.indexer.api,
|
||||
intNetwork
|
||||
)
|
||||
: undefined;
|
||||
this.aggregator = new Aggregator(
|
||||
this.config.services.aggregator.http,
|
||||
this.config.services.aggregator.ws,
|
||||
this.config.basicAuth
|
||||
this.config.basicAuth,
|
||||
logger,
|
||||
);
|
||||
this.priceFeed = new PriceFeed(
|
||||
this.config.services.priceFeed.api,
|
||||
this.config.basicAuth
|
||||
);
|
||||
this.exchange = new Exchange(this);
|
||||
this.pmm = new Pmm(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
"rpc": "https://opbnb-mainnet-rpc.bnbchain.org",
|
||||
"baseCurrencyName": "BNB",
|
||||
"contracts": {
|
||||
"WETH": "0x4200000000000000000000000000000000000006"
|
||||
"WETH": "0x4200000000000000000000000000000000000006",
|
||||
"curveRegistry": ""
|
||||
}
|
||||
},
|
||||
"3": {
|
||||
@@ -96,10 +97,10 @@
|
||||
"shortName": "Arbitrum",
|
||||
"code": "arb",
|
||||
"rpc": "https://arb1.arbitrum.io/rpc",
|
||||
"baseCurrencyName": "ARB",
|
||||
"baseCurrencyName": "ETH",
|
||||
"contracts": {
|
||||
"WETH": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
||||
"curveRegistiry": "0x445FE580eF8d70FF569aB36e80c647af338db351"
|
||||
"curveRegistry": "0x445FE580eF8d70FF569aB36e80c647af338db351"
|
||||
}
|
||||
},
|
||||
"4002": {
|
||||
@@ -192,5 +193,57 @@
|
||||
"WETH": "",
|
||||
"curveRegistry": ""
|
||||
}
|
||||
},
|
||||
"2525": {
|
||||
"chainId": "2525",
|
||||
"label": "inEVM",
|
||||
"shortName": "inEVM",
|
||||
"code": "inevm",
|
||||
"baseCurrencyName": "INJ",
|
||||
"rpc": "https://inevm.calderachain.xyz/http/",
|
||||
"explorer": "https://explorer.injective.network/",
|
||||
"contracts": {
|
||||
"WETH": "0x4C3A213bd5e8c4BD70a8396d6F3C8302571598Cd",
|
||||
"curveRegistry": ""
|
||||
}
|
||||
},
|
||||
"59144": {
|
||||
"chainId": "59144",
|
||||
"label": "Linea",
|
||||
"shortName": "Linea",
|
||||
"code": "linea",
|
||||
"baseCurrencyName": "ETH",
|
||||
"rpc": "https://rpc.linea.build/",
|
||||
"explorer": "https://lineascan.build/",
|
||||
"contracts": {
|
||||
"WETH": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f",
|
||||
"curveRegistry": ""
|
||||
}
|
||||
},
|
||||
"43114": {
|
||||
"chainId": "43114",
|
||||
"label": "Avalanche Network",
|
||||
"shortName": "Avax",
|
||||
"code": "avax",
|
||||
"baseCurrencyName": "AVAX",
|
||||
"rpc": "https://api.avax.network/ext/bc/C/rpc/",
|
||||
"explorer": "https://snowtrace.io/",
|
||||
"contracts": {
|
||||
"WETH": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7",
|
||||
"curveRegistry": ""
|
||||
}
|
||||
},
|
||||
"8453": {
|
||||
"chainId": "8453",
|
||||
"label": "Base",
|
||||
"shortName": "BASE",
|
||||
"code": "base",
|
||||
"baseCurrencyName": "ETH",
|
||||
"rpc": "https://mainnet.base.org/",
|
||||
"explorer": "https://basescan.org/",
|
||||
"contracts": {
|
||||
"WETH": "0x4200000000000000000000000000000000000006",
|
||||
"curveRegistry": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"production": {
|
||||
"analyticsAPI": "https://trade.orion.xyz/api/stats",
|
||||
"referralAPI": "https://trade.orion.xyz/referral-api",
|
||||
"networks": {
|
||||
"1": {
|
||||
@@ -95,7 +94,7 @@
|
||||
}
|
||||
},
|
||||
"42161": {
|
||||
"api": "https://trade.orion.xyz/arbitrum-mainnet",
|
||||
"api": "https://trade.orion.xyz/arbitrum-one",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
@@ -129,11 +128,82 @@
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"2525": {
|
||||
"api": "https://trade.orion.xyz/inevm-mainnet",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"59144": {
|
||||
"api": "https://trade.orion.xyz/linea-mainnet",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"43114": {
|
||||
"api": "https://trade.orion.xyz/avalanche-c-chain",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"8453": {
|
||||
"api": "https://trade.orion.xyz/base-mainnet",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"testing": {
|
||||
"analyticsAPI": "https://trade.orion.xyz/api/stats",
|
||||
"referralAPI": "https://testing.orion.xyz/referral-api",
|
||||
"networks": {
|
||||
"97": {
|
||||
@@ -248,7 +318,6 @@
|
||||
}
|
||||
},
|
||||
"staging": {
|
||||
"analyticsAPI": "https://trade.orion.xyz/api/stats",
|
||||
"referralAPI": "https://staging.orion.xyz/referral-api",
|
||||
"networks": {
|
||||
"1": {
|
||||
@@ -340,11 +409,118 @@
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"42161": {
|
||||
"api": "https://staging.orion.xyz/arbitrum-one",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"204": {
|
||||
"api": "https://staging.orion.xyz/opbnb-mainnet",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"2525": {
|
||||
"api": "https://staging.orion.xyz/inevm-mainnet",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"59144": {
|
||||
"api": "https://staging.orion.xyz/linea-mainnet",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"43114": {
|
||||
"api": "https://staging.orion.xyz/avalanche-c-chain",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"8453": {
|
||||
"api": "https://staging.orion.xyz/base-mainnet",
|
||||
"services": {
|
||||
"aggregator": {
|
||||
"http": "/backend",
|
||||
"ws": "/v1"
|
||||
},
|
||||
"blockchain": {
|
||||
"http": ""
|
||||
},
|
||||
"priceFeed": {
|
||||
"all": "/price-feed"
|
||||
},
|
||||
"indexer": {
|
||||
"http": "/orion-indexer/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"experimental": {
|
||||
"analyticsAPI": "https://trade.orion.xyz/api/stats",
|
||||
"referralAPI": "https://testing.orion.xyz/referral-api",
|
||||
"networks": {
|
||||
"97": {
|
||||
@@ -386,7 +562,6 @@
|
||||
}
|
||||
},
|
||||
"kucoin-production": {
|
||||
"analyticsAPI": "https://trade.orion.xyz/api/stats",
|
||||
"referralAPI": "https://trade.orion.xyz/referral-api",
|
||||
"networks": {
|
||||
"1": {
|
||||
|
||||
@@ -16,14 +16,14 @@ export const pureEnvNetworksSchema = z.object({
|
||||
}),
|
||||
indexer: z.object({
|
||||
http: z.string(),
|
||||
}),
|
||||
}).optional(),
|
||||
}),
|
||||
rpc: z.string().optional(),
|
||||
liquidityMigratorAddress: z.string().optional(),
|
||||
});
|
||||
|
||||
export const pureEnvPayloadSchema = z.object({
|
||||
analyticsAPI: z.string().url(),
|
||||
analyticsAPI: z.string().url().optional(),
|
||||
referralAPI: z.string().url(),
|
||||
networks: z.record(
|
||||
z.nativeEnum(SupportedChainId),
|
||||
|
||||
@@ -17,4 +17,8 @@ export const productionChains = [
|
||||
SupportedChainId.OKC,
|
||||
SupportedChainId.ARBITRUM,
|
||||
SupportedChainId.OPBNB,
|
||||
SupportedChainId.INEVM,
|
||||
SupportedChainId.LINEA,
|
||||
SupportedChainId.AVAX,
|
||||
SupportedChainId.BASE,
|
||||
];
|
||||
|
||||
@@ -1 +1 @@
|
||||
export default ['ftm', 'bsc', 'eth', 'polygon', 'okc', 'arb', 'drip', 'opbnb'] as const;
|
||||
export default ['ftm', 'bsc', 'eth', 'polygon', 'okc', 'arb', 'drip', 'opbnb', 'inevm', 'linea', 'avax', 'base'] as const;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export default ['FTM', 'BSC', 'ETH', 'POLYGON', 'OKC', 'ARB'] as const;
|
||||
export default ['FTM', 'BSC', 'ETH', 'POLYGON', 'OKC', 'ARB', 'OPBNB', 'INEVM', 'LINEA', 'AVAX', 'BASE'] as const;
|
||||
|
||||
@@ -1,35 +1,16 @@
|
||||
import { ethers } from 'ethers';
|
||||
import { ethers, keccak256 } from 'ethers';
|
||||
import type { Order } from '../types.js';
|
||||
|
||||
const hashOrder = (order: Order) => ethers.solidityPackedKeccak256(
|
||||
[
|
||||
'uint8',
|
||||
'address',
|
||||
'address',
|
||||
'address',
|
||||
'address',
|
||||
'address',
|
||||
'uint64',
|
||||
'uint64',
|
||||
'uint64',
|
||||
'uint64',
|
||||
'uint64',
|
||||
'uint8',
|
||||
],
|
||||
[
|
||||
'0x03',
|
||||
order.senderAddress,
|
||||
order.matcherAddress,
|
||||
order.baseAsset,
|
||||
order.quoteAsset,
|
||||
order.matcherFeeAsset,
|
||||
order.amount,
|
||||
order.price,
|
||||
order.matcherFee,
|
||||
order.nonce,
|
||||
order.expiration,
|
||||
order.buySide === 1 ? '0x01' : '0x00',
|
||||
],
|
||||
);
|
||||
const ORDER_TYPEHASH = "0xb5132db62dfceb466f2f8aee7a039db36a99772e5a9771d28388a5f9baad7c54"
|
||||
|
||||
export default hashOrder;
|
||||
export default function getOrderHash(order: Order) {
|
||||
const abiCoder = ethers.AbiCoder.defaultAbiCoder()
|
||||
|
||||
const { senderAddress, matcherAddress, baseAsset, quoteAsset, matcherFeeAsset, amount, price, matcherFee, nonce, expiration, buySide } = order
|
||||
const orderBytes = abiCoder.encode(
|
||||
["bytes32", "address", "address", "address", "address", "address", "uint64", "uint64", "uint64", "uint64", "uint64", "uint8"],
|
||||
[ORDER_TYPEHASH, senderAddress, matcherAddress, baseAsset, quoteAsset, matcherFeeAsset, amount, price, matcherFee, nonce, expiration, buySide]
|
||||
)
|
||||
|
||||
return keccak256(orderBytes)
|
||||
}
|
||||
@@ -25,6 +25,10 @@ import httpToWS from '../../utils/httpToWS.js';
|
||||
import { ethers } from 'ethers';
|
||||
import orderSchema from './schemas/orderSchema.js';
|
||||
import { fetchWithValidation } from 'simple-typed-fetch';
|
||||
import { pmmOrderSchema } from '../../Unit/Pmm/schemas/order';
|
||||
// import hmacSHA256 from "crypto-js/hmac-sha256";
|
||||
// import Hex from "crypto-js/enc-hex";
|
||||
// const crypto = require('crypto')
|
||||
|
||||
class Aggregator {
|
||||
private readonly apiUrl: string;
|
||||
@@ -37,11 +41,16 @@ class Aggregator {
|
||||
return this.apiUrl;
|
||||
}
|
||||
|
||||
public logger: ((message: string) => void) | undefined;
|
||||
|
||||
constructor(
|
||||
httpAPIUrl: string,
|
||||
wsAPIUrl: string,
|
||||
basicAuth?: BasicAuthCredentials
|
||||
basicAuth?: BasicAuthCredentials,
|
||||
logger?: ((message: string) => void) | undefined
|
||||
) {
|
||||
this.logger = logger;
|
||||
|
||||
// const oaUrl = new URL(apiUrl);
|
||||
// const oaWsProtocol = oaUrl.protocol === 'https:' ? 'wss' : 'ws';
|
||||
// const aggregatorWsUrl = `${oaWsProtocol}://${oaUrl.host + (oaUrl.pathname === '/'
|
||||
@@ -49,7 +58,7 @@ class Aggregator {
|
||||
// : oaUrl.pathname)}/v1`;
|
||||
|
||||
this.apiUrl = httpAPIUrl;
|
||||
this.ws = new AggregatorWS(httpToWS(wsAPIUrl));
|
||||
this.ws = new AggregatorWS(httpToWS(wsAPIUrl), undefined, logger);
|
||||
this.basicAuth = basicAuth;
|
||||
|
||||
this.getHistoryAtomicSwaps = this.getHistoryAtomicSwaps.bind(this);
|
||||
@@ -59,6 +68,7 @@ class Aggregator {
|
||||
this.getSwapInfo = this.getSwapInfo.bind(this);
|
||||
this.getCrossChainAssetsByNetwork = this.getCrossChainAssetsByNetwork.bind(this);
|
||||
this.getTradeProfits = this.getTradeProfits.bind(this);
|
||||
this.getStableCoins = this.getStableCoins.bind(this);
|
||||
this.placeAtomicSwap = this.placeAtomicSwap.bind(this);
|
||||
this.placeOrder = this.placeOrder.bind(this);
|
||||
this.placeLockOrder = this.placeLockOrder.bind(this);
|
||||
@@ -70,6 +80,7 @@ class Aggregator {
|
||||
this.getPoolReserves = this.getPoolReserves.bind(this);
|
||||
this.getVersion = this.getVersion.bind(this);
|
||||
this.getPrices = this.getPrices.bind(this);
|
||||
this.getIsCexLiquidityAvailable = this.getIsCexLiquidityAvailable.bind(this);
|
||||
}
|
||||
|
||||
get basicAuthHeaders() {
|
||||
@@ -383,6 +394,16 @@ class Aggregator {
|
||||
);
|
||||
};
|
||||
|
||||
getStableCoins = () => {
|
||||
const url = new URL(`${this.apiUrl}/api/v1/tokens/stable/`);
|
||||
return fetchWithValidation(
|
||||
url.toString(),
|
||||
z.array(z.string()),
|
||||
{ headers: this.basicAuthHeaders },
|
||||
errorSchema,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Placing atomic swap. Placement must take place on the target chain.
|
||||
* @param secretHash Secret hash
|
||||
@@ -422,6 +443,116 @@ class Aggregator {
|
||||
url.searchParams.append('limit', limit.toString());
|
||||
return fetchWithValidation(url.toString(), atomicSwapHistorySchema, { headers: this.basicAuthHeaders });
|
||||
};
|
||||
|
||||
getIsCexLiquidityAvailable = (
|
||||
assetIn: string,
|
||||
assetOut: string,
|
||||
) => {
|
||||
const url = new URL(`${this.apiUrl}/api/v1/pairs/cex/liquidity/${assetIn}/${assetOut}`);
|
||||
|
||||
return fetchWithValidation(
|
||||
url.toString(),
|
||||
z.boolean(),
|
||||
{ headers: this.basicAuthHeaders },
|
||||
errorSchema,
|
||||
);
|
||||
};
|
||||
|
||||
// private encode_utf8(s: string) {
|
||||
// return unescape(encodeURIComponent(s));
|
||||
// }
|
||||
|
||||
// @ts-expect-error: TODO: please remove this line!
|
||||
private sign(message: string, key: string) {
|
||||
// return crypto.createHmac('sha256', this.encode_utf8(key))
|
||||
// .update(this.encode_utf8(message))
|
||||
// .digest('hex');
|
||||
return '';
|
||||
}
|
||||
|
||||
private generateHeaders(body: any, method: string, path: string, timestamp: number, apiKey: string, secretKey: string) {
|
||||
const sortedBody = Object.keys(body)
|
||||
.sort()
|
||||
.map((key) => (
|
||||
`${key}=${body[key]}`
|
||||
)).join('&');
|
||||
|
||||
const payload = timestamp + method.toUpperCase() + path + sortedBody;
|
||||
|
||||
const signature = this.sign(payload, secretKey);
|
||||
|
||||
const httpOptions = {
|
||||
headers: {
|
||||
'API-KEY': apiKey,
|
||||
'ACCESS-TIMESTAMP': timestamp.toString(),
|
||||
'ACCESS-SIGN': signature
|
||||
}
|
||||
};
|
||||
return httpOptions;
|
||||
}
|
||||
|
||||
public async RFQOrder(
|
||||
tokenFrom: string,
|
||||
tokenTo: string,
|
||||
fromTokenAmount: string,
|
||||
apiKey: string, //
|
||||
secretKey: string,
|
||||
wallet: string
|
||||
): Promise<z.infer<typeof pmmOrderSchema>> {
|
||||
// Making the order structure
|
||||
const
|
||||
path = '/rfq';
|
||||
const url = `${this.apiUrl}/api/v1/integration/pmm` + path;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const data = {
|
||||
baseToken: tokenFrom, // USDT
|
||||
quoteToken: tokenTo, // ORN
|
||||
amount: fromTokenAmount, // 100
|
||||
taker: wallet,
|
||||
feeBps: 0
|
||||
};
|
||||
const method = 'POST';
|
||||
const timestamp = Date.now();
|
||||
const signatureHeaders = this.generateHeaders(data, method, path, timestamp, apiKey, secretKey);
|
||||
const compiledHeaders = { ...headers, ...signatureHeaders.headers, };
|
||||
const body = JSON.stringify(data)
|
||||
;
|
||||
|
||||
const res = pmmOrderSchema.parse({});
|
||||
|
||||
try {
|
||||
const result = await fetch(url, {
|
||||
headers: compiledHeaders,
|
||||
method,
|
||||
body
|
||||
});
|
||||
|
||||
const json = await result.json();
|
||||
const parseResult = pmmOrderSchema.safeParse(json);
|
||||
|
||||
if (!parseResult.success) {
|
||||
// Try to parse error answer
|
||||
const errorSchema = z.object({ error: z.object({ code: z.number(), reason: z.string() }) });
|
||||
|
||||
const errorParseResult = errorSchema.safeParse(json);
|
||||
|
||||
if (!errorParseResult.success) { throw Error(`Unrecognized answer from aggregator: ${json}`); }
|
||||
|
||||
throw Error(errorParseResult.data.error.reason);
|
||||
}
|
||||
|
||||
res.order = parseResult.data.order;
|
||||
res.signature = parseResult.data.signature;
|
||||
res.error = '';
|
||||
res.success = true;
|
||||
// return result;
|
||||
} catch (err) {
|
||||
res.error = `${err}`;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export * as schemas from './schemas/index.js';
|
||||
|
||||
@@ -49,6 +49,7 @@ const swapInfoBase = z.object({
|
||||
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(),
|
||||
autoSlippage: z.number().optional(),
|
||||
});
|
||||
|
||||
const swapInfoByAmountIn = swapInfoBase.extend({
|
||||
|
||||
@@ -66,10 +66,11 @@ type PairConfigSubscription = {
|
||||
|
||||
type AggregatedOrderbookSubscription = {
|
||||
payload: string
|
||||
dc?: number
|
||||
callback: (
|
||||
asks: OrderbookItem[],
|
||||
bids: OrderbookItem[],
|
||||
pair: string
|
||||
pair: string,
|
||||
) => void
|
||||
errorCb?: (message: string) => void
|
||||
}
|
||||
@@ -195,9 +196,10 @@ class AggregatorWS {
|
||||
|
||||
readonly basicAuth?: BasicAuthCredentials | undefined;
|
||||
|
||||
constructor(wsUrl: string, basicAuth?: BasicAuthCredentials) {
|
||||
constructor(wsUrl: string, basicAuth?: BasicAuthCredentials, logger?: ((message: string) => void) | undefined) {
|
||||
this.wsUrl = wsUrl;
|
||||
this.basicAuth = basicAuth;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
private messageQueue: BufferLike[] = [];
|
||||
@@ -254,7 +256,7 @@ class AggregatorWS {
|
||||
subscription: Subscription[T],
|
||||
prevSubscriptionId?: string
|
||||
) {
|
||||
const id = type === 'aobus'
|
||||
const id = type === SubscriptionType.AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE
|
||||
? ((subscription as any).payload as string) // TODO: Refactor!!!
|
||||
: uuidv4();
|
||||
|
||||
@@ -264,6 +266,12 @@ class AggregatorWS {
|
||||
subRequest['T'] = type;
|
||||
subRequest['id'] = id;
|
||||
|
||||
if ('dc' in subscription) {
|
||||
if (typeof subscription.dc === 'number') {
|
||||
subRequest['dc'] = subscription.dc;
|
||||
}
|
||||
}
|
||||
|
||||
if ('payload' in subscription) {
|
||||
if (typeof subscription.payload === 'string') {
|
||||
subRequest['S'] = subscription.payload;
|
||||
@@ -371,11 +379,11 @@ class AggregatorWS {
|
||||
delete this.subscriptions[SubscriptionType.ASSET_PAIR_CONFIG_UPDATES_SUBSCRIBE]?.[newestSubId];
|
||||
// !!! swap info subscription is uuid that contains hyphen
|
||||
} else if (isOrderBooksSubscription(newestSubId)) { // is pair name(AGGREGATED_ORDER_BOOK_UPDATE)
|
||||
const aobSubscriptions = this.subscriptions[SubscriptionType.AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE];
|
||||
if (aobSubscriptions) {
|
||||
const targetAobSub = Object.entries(aobSubscriptions).find(([, value]) => value?.payload === newestSubId);
|
||||
if (targetAobSub) {
|
||||
const [key] = targetAobSub;
|
||||
const aobusSubscriptions = this.subscriptions[SubscriptionType.AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE];
|
||||
if (aobusSubscriptions) {
|
||||
const targetAobusSub = Object.entries(aobusSubscriptions).find(([, value]) => value?.payload === newestSubId);
|
||||
if (targetAobusSub) {
|
||||
const [key] = targetAobusSub;
|
||||
delete this.subscriptions[SubscriptionType.AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE]?.[key];
|
||||
}
|
||||
}
|
||||
@@ -535,6 +543,7 @@ class AggregatorWS {
|
||||
marketAmountIn: json.usd.mi,
|
||||
difference: json.usd.d,
|
||||
},
|
||||
autoSlippage: json.sl,
|
||||
};
|
||||
|
||||
switch (json.k) { // kind
|
||||
|
||||
@@ -48,6 +48,7 @@ const swapInfoSchemaBase = baseMessageSchema.extend({
|
||||
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(),
|
||||
sl: z.number().optional(),
|
||||
});
|
||||
|
||||
const swapInfoSchemaByAmountIn = swapInfoSchemaBase.extend({
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
pairStatusSchema,
|
||||
pricesWithQuoteAssetSchema,
|
||||
referralDataSchema,
|
||||
pmmSchema
|
||||
} from './schemas/index.js';
|
||||
import type redeemOrderSchema from '../Aggregator/schemas/redeemOrderSchema.js';
|
||||
import { sourceAtomicHistorySchema, targetAtomicHistorySchema } from './schemas/atomicHistorySchema.js';
|
||||
@@ -82,6 +83,7 @@ class BlockchainService {
|
||||
this.getAuthToken = this.getAuthToken.bind(this);
|
||||
this.getCirculatingSupply = this.getCirculatingSupply.bind(this);
|
||||
this.getInfo = this.getInfo.bind(this);
|
||||
this.getPmmInfo = this.getPmmInfo.bind(this);
|
||||
this.getPoolsConfig = this.getPoolsConfig.bind(this);
|
||||
this.getPoolsInfo = this.getPoolsInfo.bind(this);
|
||||
this.getPoolsLpAndStaked = this.getPoolsLpAndStaked.bind(this);
|
||||
@@ -111,6 +113,8 @@ class BlockchainService {
|
||||
this.getBlockNumber = this.getBlockNumber.bind(this);
|
||||
this.getRedeemOrderBySecretHash = this.getRedeemOrderBySecretHash.bind(this);
|
||||
this.claimOrder = this.claimOrder.bind(this);
|
||||
this.getGasLimits = this.getGasLimits.bind(this);
|
||||
this.getExchangeContractWalletBalance = this.getExchangeContractWalletBalance.bind(this);
|
||||
}
|
||||
|
||||
get basicAuthHeaders() {
|
||||
@@ -175,6 +179,8 @@ class BlockchainService {
|
||||
|
||||
getInfo = () => fetchWithValidation(`${this.apiUrl}/api/info`, infoSchema);
|
||||
|
||||
getPmmInfo = () => fetchWithValidation(`${this.apiUrl}/api/pmm-info`, pmmSchema);
|
||||
|
||||
getPoolsConfig = () => fetchWithValidation(
|
||||
`${this.apiUrl}/api/pools/config`,
|
||||
poolsConfigSchema,
|
||||
@@ -484,6 +490,18 @@ class BlockchainService {
|
||||
body: JSON.stringify(secretHashes),
|
||||
},
|
||||
);
|
||||
|
||||
getGasLimits = () => fetchWithValidation(
|
||||
`${this.apiUrl}/api/baseLimits`,
|
||||
z.record(z.number()),
|
||||
{ headers: this.basicAuthHeaders }
|
||||
);
|
||||
|
||||
getExchangeContractWalletBalance = (exchangeContractAddress: string) => fetchWithValidation(
|
||||
`${this.apiUrl}/api/broker/getWalletBalance/${exchangeContractAddress}`,
|
||||
z.record(z.string()),
|
||||
{ headers: this.basicAuthHeaders }
|
||||
);
|
||||
}
|
||||
|
||||
export * as schemas from './schemas/index.js';
|
||||
|
||||
@@ -13,5 +13,6 @@ export { default as poolsLpAndStakedSchema } from './poolsLpAndStakedSchema.js';
|
||||
export { default as userVotesSchema } from './userVotesSchema.js';
|
||||
export { default as userEarnedSchema } from './userEarnedSchema.js';
|
||||
export { default as poolsV3InfoSchema } from './poolsV3InfoSchema.js';
|
||||
export { default as pmmSchema } from './pmmSchema.js';
|
||||
export { pricesWithQuoteAssetSchema } from './pricesWithQuoteAssetSchema.js';
|
||||
export { referralDataSchema } from './referralDataSchema.js';
|
||||
7
src/services/BlockchainService/schemas/pmmSchema.ts
Normal file
7
src/services/BlockchainService/schemas/pmmSchema.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
const pmmSchema = z.object({
|
||||
orionPMMRouterContractAddress: z.string()
|
||||
});
|
||||
|
||||
export default pmmSchema
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { z } from 'zod';
|
||||
|
||||
export const referralDataSchema = z.object({
|
||||
referer: z.string(),
|
||||
referer: z.string().nullable(),
|
||||
isReferral: z.boolean(),
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
PoolV2InfoResponseSchema,
|
||||
testIncrementorSchema,
|
||||
veORNInfoResponseSchema,
|
||||
votingInfoResponseSchema
|
||||
votingInfoResponseSchema,
|
||||
} from './schemas';
|
||||
import { fetchWithValidation } from 'simple-typed-fetch';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
@@ -94,6 +94,7 @@ class IndexerService {
|
||||
this.veORNInfo = this.veORNInfo.bind(this);
|
||||
this.listAmount = this.listAmount.bind(this);
|
||||
this.getAmountByORN = this.getAmountByORN.bind(this);
|
||||
this.getAmountAt = this.getAmountAt.bind(this);
|
||||
this.getAmountAtCurrent = this.getAmountAtCurrent.bind(this);
|
||||
this.getVotingInfo = this.getVotingInfo.bind(this);
|
||||
}
|
||||
@@ -117,6 +118,23 @@ class IndexerService {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} amount - amount
|
||||
* @param {number} [timestamp = Date.now()] - timestamp, defaults to current time
|
||||
*/
|
||||
readonly getAmountAt = (
|
||||
amount: number,
|
||||
timestamp = Date.now()
|
||||
): BigNumber => {
|
||||
const finalTimestamp = timestamp / 1000;
|
||||
|
||||
// sqrt
|
||||
return BigNumber(amount).dividedBy(this.getK(finalTimestamp));
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated since version 69 in favor of getAmountAt
|
||||
*/
|
||||
readonly getAmountAtCurrent = (amount: number): BigNumber => {
|
||||
const timestamp = Date.now() / 1000;
|
||||
|
||||
@@ -134,8 +152,7 @@ class IndexerService {
|
||||
const multSQRT = deltaDaysBN.dividedBy(WEEK_DAYS).sqrt();
|
||||
const multCUBE = deltaDaysBN.dividedBy(alpha).pow(3);
|
||||
|
||||
return BigNumber(amountToken)
|
||||
.multipliedBy(multSQRT.plus(multCUBE));
|
||||
return BigNumber(amountToken).multipliedBy(multSQRT.plus(multCUBE));
|
||||
};
|
||||
|
||||
readonly getVotingInfo = (userAddress?: string) => {
|
||||
@@ -208,7 +225,11 @@ class IndexerService {
|
||||
});
|
||||
};
|
||||
|
||||
readonly poolV2Info = (token0: string, token1: string, address: string | undefined) => {
|
||||
readonly poolV2Info = (
|
||||
token0: string,
|
||||
token1: string,
|
||||
address: string | undefined
|
||||
) => {
|
||||
return fetchWithValidation(this.apiUrl, PoolV2InfoResponseSchema, {
|
||||
method: 'POST',
|
||||
body: this.makeRPCPayload({
|
||||
|
||||
@@ -2,7 +2,7 @@ import WebSocket from 'isomorphic-ws';
|
||||
import { z } from 'zod';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import priceFeedSubscriptions from './priceFeedSubscriptions.js';
|
||||
import { tickerInfoSchema, candleSchema } from './schemas/index.js';
|
||||
import { tickerInfoSchema, candleSchema, cexPricesSchema } from './schemas/index.js';
|
||||
import priceSchema from './schemas/priceSchema.js';
|
||||
import type { Json } from '../../../types.js';
|
||||
import allTickersSchema from './schemas/allTickersSchema.js';
|
||||
@@ -24,6 +24,10 @@ export const subscriptions = {
|
||||
schema: candleSchema,
|
||||
payload: true as const,
|
||||
},
|
||||
[priceFeedSubscriptions.CEX]: {
|
||||
schema: cexPricesSchema,
|
||||
payload: false as const,
|
||||
},
|
||||
};
|
||||
|
||||
export type SubscriptionType = keyof typeof subscriptions;
|
||||
|
||||
@@ -3,6 +3,7 @@ const priceFeedSubscriptions = {
|
||||
ALL_TICKERS: 'allTickers',
|
||||
LAST_PRICE: 'lastPrice',
|
||||
CANDLE: 'candle',
|
||||
CEX: 'cexPrices'
|
||||
} as const;
|
||||
|
||||
export default priceFeedSubscriptions;
|
||||
|
||||
31
src/services/PriceFeed/ws/schemas/cexPricesSchema.ts
Normal file
31
src/services/PriceFeed/ws/schemas/cexPricesSchema.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
const cexPriceTickerInfoSchema = z.tuple([
|
||||
z.string(), // pair name
|
||||
z.number(), // lastPrice
|
||||
]).transform(([pairName, lastPrice]) => ({
|
||||
pairName:pairName.toUpperCase(),
|
||||
lastPrice,
|
||||
}));
|
||||
|
||||
type CEXPriceTickerInfo = z.infer<typeof cexPriceTickerInfoSchema>
|
||||
|
||||
const cexPricesSchema = z.unknown().array()
|
||||
.transform((tickers) => {
|
||||
const data = [...tickers];
|
||||
data.shift();
|
||||
const parsedData = cexPriceTickerInfoSchema.array().parse(data);
|
||||
return parsedData.reduce<
|
||||
Partial<
|
||||
Record<
|
||||
string,
|
||||
CEXPriceTickerInfo
|
||||
>
|
||||
>
|
||||
>((prev, pairData) => ({
|
||||
...prev,
|
||||
[pairData.pairName]: pairData,
|
||||
}), {});
|
||||
});
|
||||
|
||||
export default cexPricesSchema;
|
||||
@@ -2,3 +2,4 @@ export { default as tickerInfoSchema } from './tickerInfoSchema.js';
|
||||
export { default as candleSchema } from './candleSchema.js';
|
||||
export { default as priceSchema } from './priceSchema.js';
|
||||
export { default as allTickersSchema } from './allTickersSchema.js';
|
||||
export { default as cexPricesSchema } from './cexPricesSchema.js';
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
aggregatedHistorySchema,
|
||||
inviteCodeLinkSchema,
|
||||
contractsAddressesSchema,
|
||||
allTimeLeadersSchema,
|
||||
} from './schemas/index.js';
|
||||
import type { SupportedChainId } from '../../types.js';
|
||||
|
||||
@@ -71,6 +72,7 @@ class ReferralSystem {
|
||||
this.claimRewards = this.claimRewards.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);
|
||||
@@ -231,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`,
|
||||
|
||||
11
src/services/ReferralSystem/schemas/allTimeLeadersSchema.ts
Normal file
11
src/services/ReferralSystem/schemas/allTimeLeadersSchema.ts
Normal 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;
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
11
src/types.ts
11
src/types.ts
@@ -109,6 +109,10 @@ export enum SupportedChainId {
|
||||
POLYGON = '137',
|
||||
OKC = '66',
|
||||
OPBNB = '204',
|
||||
INEVM = '2525',
|
||||
LINEA = '59144',
|
||||
AVAX = '43114',
|
||||
BASE = '8453',
|
||||
|
||||
POLYGON_TESTNET = '80001',
|
||||
FANTOM_TESTNET = '4002',
|
||||
@@ -229,6 +233,7 @@ export type SwapInfoBase = {
|
||||
marketAmountIn: number | undefined
|
||||
difference: string | undefined
|
||||
} | undefined
|
||||
autoSlippage: number | undefined
|
||||
}
|
||||
|
||||
export type SwapInfoByAmountIn = SwapInfoBase & {
|
||||
@@ -285,12 +290,12 @@ export type VerboseUnitConfig = {
|
||||
// http://10.23.5.11:3003/,
|
||||
// https://price-feed:3003/
|
||||
}
|
||||
indexer: {
|
||||
indexer?: {
|
||||
api: string
|
||||
// For example:
|
||||
// http://localhost:3004/,
|
||||
// http://
|
||||
}
|
||||
} | undefined
|
||||
}
|
||||
basicAuth?: BasicAuthCredentials
|
||||
}
|
||||
@@ -300,7 +305,7 @@ export type KnownEnv = typeof knownEnvs[number];
|
||||
export type Json = string | number | boolean | null | Json[] | { [key: string]: Json };
|
||||
|
||||
export type EnvConfig = {
|
||||
analyticsAPI: string
|
||||
analyticsAPI: string | undefined
|
||||
referralAPI: string
|
||||
networks: Partial<
|
||||
Record<
|
||||
|
||||
Reference in New Issue
Block a user