mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-03-25 15:17:40 +03:00
Merge branch 'refs/heads/main' into OP-5247-frontend-optimization
# Conflicts: # package.json
This commit is contained in:
@@ -24,10 +24,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];
|
||||
@@ -96,7 +101,7 @@ export default class Orion {
|
||||
// api: networkConfig.api,
|
||||
nodeJsonRpc: networkConfig.nodeJsonRpc,
|
||||
services: networkConfig.services,
|
||||
});
|
||||
}, logger);
|
||||
return {
|
||||
...acc,
|
||||
[chainId]: unit,
|
||||
|
||||
@@ -79,6 +79,6 @@ export default class Pmm {
|
||||
const contract = new ethers.Contract(this.contractAddress, orionRFQContractABI, signer);
|
||||
|
||||
// @ts-ignore
|
||||
return contract.fillOrderRFQ(order.quotation, order.signature, BigInt(0));
|
||||
return contract.fillOrderRFQ(order.order, order.signature, BigInt(0));
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ export const pmmOrderQuotationSchema = z.object({
|
||||
});
|
||||
|
||||
export const pmmOrderSchema = z.object({
|
||||
quotation: pmmOrderQuotationSchema.default({}),
|
||||
order: pmmOrderQuotationSchema.default({}),
|
||||
signature: z.string().default(''),
|
||||
success: z.boolean().default(false),
|
||||
error: z.string().default(''),
|
||||
|
||||
@@ -41,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) {
|
||||
@@ -118,7 +121,8 @@ export default class Unit {
|
||||
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,
|
||||
|
||||
@@ -19,9 +19,10 @@ import httpToWS from '../../utils/httpToWS.js';
|
||||
import { ethers } from 'ethers';
|
||||
import orderSchema from './schemas/orderSchema.js';
|
||||
import { fetchWithValidation } from 'simple-typed-fetch';
|
||||
import hmacSHA256 from "crypto-js/hmac-sha256";
|
||||
import Hex from "crypto-js/enc-hex";
|
||||
import {pmmOrderSchema} from "../../Unit/Pmm/schemas/order";
|
||||
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;
|
||||
@@ -34,11 +35,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 === '/'
|
||||
@@ -46,7 +52,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);
|
||||
@@ -55,6 +61,7 @@ class Aggregator {
|
||||
this.getPairsList = this.getPairsList.bind(this);
|
||||
this.getSwapInfo = this.getSwapInfo.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.cancelOrder = this.cancelOrder.bind(this);
|
||||
@@ -334,6 +341,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
|
||||
@@ -373,24 +390,24 @@ class Aggregator {
|
||||
return fetchWithValidation(url.toString(), atomicSwapHistorySchema, { headers: this.basicAuthHeaders });
|
||||
};
|
||||
|
||||
// private encode_utf8(s: string) {
|
||||
// return unescape(encodeURIComponent(s));
|
||||
// }
|
||||
|
||||
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 sign(message : string, key: string) {
|
||||
return hmacSHA256(
|
||||
this.encode_utf8(message),
|
||||
this.encode_utf8(key)
|
||||
).toString(Hex);
|
||||
}
|
||||
|
||||
private generateHeaders(body : any, method : string, path : string, timestamp : number, apiKey : string, secretKey : string) {
|
||||
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('&');
|
||||
.sort()
|
||||
.map((key) => (
|
||||
`${key}=${body[key]}`
|
||||
)).join('&');
|
||||
|
||||
const payload = timestamp + method.toUpperCase() + path + sortedBody;
|
||||
|
||||
@@ -407,40 +424,38 @@ class Aggregator {
|
||||
}
|
||||
|
||||
public async RFQOrder(
|
||||
tokenFrom: string,
|
||||
tokenTo: string,
|
||||
fromTokenAmount: string,
|
||||
apiKey: string, //
|
||||
secretKey: string,
|
||||
wallet: string
|
||||
) : Promise<z.infer<typeof pmmOrderSchema>> {
|
||||
|
||||
tokenFrom: string,
|
||||
tokenTo: string,
|
||||
fromTokenAmount: string,
|
||||
apiKey: string, //
|
||||
secretKey: string,
|
||||
wallet: string
|
||||
): Promise<z.infer<typeof pmmOrderSchema>> {
|
||||
// Making the order structure
|
||||
const
|
||||
path = '/rfq'
|
||||
, url = `${this.apiUrl}/api/v1/integration/pmm`+path
|
||||
, headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
, data = {
|
||||
"baseToken":tokenFrom, // USDT
|
||||
"quoteToken":tokenTo, // ORN
|
||||
"amount": fromTokenAmount, // 100
|
||||
"taker": wallet,
|
||||
"feeBps": 0
|
||||
}
|
||||
, method = 'POST'
|
||||
, timestamp = Date.now()
|
||||
, signatureHeaders = this.generateHeaders(data, method, path, timestamp, apiKey, secretKey)
|
||||
, compiledHeaders = {...headers, ...signatureHeaders.headers, }
|
||||
, body = JSON.stringify(data)
|
||||
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)
|
||||
;
|
||||
|
||||
|
||||
let res = pmmOrderSchema.parse({});
|
||||
const res = pmmOrderSchema.parse({});
|
||||
|
||||
try {
|
||||
const result = await fetch(url,{
|
||||
const result = await fetch(url, {
|
||||
headers: compiledHeaders,
|
||||
method,
|
||||
body
|
||||
@@ -449,25 +464,23 @@ class Aggregator {
|
||||
const json = await result.json();
|
||||
const parseResult = pmmOrderSchema.safeParse(json);
|
||||
|
||||
if(!parseResult.success) {
|
||||
if (!parseResult.success) {
|
||||
// Try to parse error answer
|
||||
const errorSchema = z.object({error: z.object({code: z.number(), reason: z.string()})});
|
||||
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}`);
|
||||
if (!errorParseResult.success) { throw Error(`Unrecognized answer from aggregator: ${json}`); }
|
||||
|
||||
throw Error(errorParseResult.data.error.reason);
|
||||
}
|
||||
|
||||
res.quotation = parseResult.data.quotation;
|
||||
res.order = parseResult.data.order;
|
||||
res.signature = parseResult.data.signature;
|
||||
res.error = '';
|
||||
res.success = true;
|
||||
// return result;
|
||||
}
|
||||
catch(err) {
|
||||
} catch (err) {
|
||||
res.error = `${err}`;
|
||||
}
|
||||
return res;
|
||||
|
||||
@@ -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[] = [];
|
||||
@@ -252,7 +254,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();
|
||||
|
||||
@@ -262,6 +264,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;
|
||||
@@ -369,11 +377,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];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user