diff --git a/package.json b/package.json index 2f55c0b..5acad94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@compolabs/spark-orderbook-ts-sdk", - "version": "1.14.0", + "version": "1.14.1", "type": "module", "main": "./dist/index.сjs", "module": "./dist/index.js", @@ -43,6 +43,7 @@ }, "dependencies": { "@apollo/client": "^3.10.8", + "axios": "^1.7.7", "bignumber.js": "^9.1.2", "graphql-ws": "^5.16.0", "tsdef": "^0.0.14" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3649a2f..997517b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@apollo/client': specifier: ^3.10.8 version: 3.10.8(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + axios: + specifier: ^1.7.7 + version: 1.7.7 bignumber.js: specifier: ^9.1.2 version: 9.1.2 @@ -1140,6 +1143,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1703,6 +1709,15 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -1714,6 +1729,10 @@ packages: resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -2548,6 +2567,9 @@ packages: property-expr@2.0.6: resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4292,6 +4314,14 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 + axios@1.7.7: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.1 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + babel-jest@29.7.0(@babel/core@7.24.7): dependencies: '@babel/core': 7.24.7 @@ -5005,6 +5035,8 @@ snapshots: flatted@3.3.1: {} + follow-redirects@1.15.9: {} + for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -5020,6 +5052,12 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -6016,6 +6054,8 @@ snapshots: property-expr@2.0.6: {} + proxy-from-env@1.1.0: {} + punycode@2.3.1: {} pure-rand@6.1.0: {} diff --git a/src/IndexerApi.ts b/src/IndexerApi.ts index b3dbe1f..63fd305 100644 --- a/src/IndexerApi.ts +++ b/src/IndexerApi.ts @@ -5,6 +5,7 @@ import { Observable, } from "@apollo/client"; +import { getActiveOrdersQuery, getOrdersQuery } from "./query/indexerQuery"; import BN from "./utils/BN"; import { generateWhereFilter } from "./utils/generateWhereFilter"; import { GraphClient } from "./utils/GraphClient"; @@ -20,7 +21,6 @@ import { UserInfoParams, Volume, } from "./interface"; -import { getActiveOrdersQuery, getOrdersQuery } from "./query"; export class IndexerApi extends GraphClient { getOrders = ( diff --git a/src/SparkOrderbook.ts b/src/SparkOrderbook.ts index f1a2a9d..d27bbb6 100644 --- a/src/SparkOrderbook.ts +++ b/src/SparkOrderbook.ts @@ -22,6 +22,7 @@ import { GetActiveOrdersParams, GetOrdersParams, GetTradeOrderEventsParams, + GetUserScoreSnapshotParams, GraphClientConfig, MarketInfo, Markets, @@ -30,6 +31,7 @@ import { Order, OrderType, ProtocolFee, + SentioApiParams, SparkParams, SpotOrderWithoutTimestamp, TradeOrderEvent, @@ -42,6 +44,7 @@ import { WriteTransactionResponse, } from "./interface"; import { ReadActions } from "./ReadActions"; +import { SentioApi } from "./sentioApi"; import { WriteActions } from "./WriteActions"; export class SparkOrderbook { @@ -49,6 +52,7 @@ export class SparkOrderbook { private provider?: Provider; private options: OptionsSpark; private indexerApi?: IndexerApi; + private sentioApi?: SentioApi; constructor(params: SparkParams) { this.options = { @@ -72,6 +76,13 @@ export class SparkOrderbook { return this.indexerApi; } + private get activeSentioApi(): SentioApi { + if (!this.sentioApi) { + throw new Error("Please set the correct active indexer."); + } + return this.sentioApi; + } + async getProvider(): Promise { if (!this.provider) { this.provider = await this.providerPromise; @@ -122,6 +133,10 @@ export class SparkOrderbook { this.indexerApi = new IndexerApi(indexer); } + setSentioConfig(params: SentioApiParams): void { + this.sentioApi = new SentioApi(params); + } + async createOrder( order: CreateOrderParams, ): Promise { @@ -334,6 +349,10 @@ export class SparkOrderbook { return read.fetchMinOrderPrice(); } + async getUserScoreSnapshot(params: GetUserScoreSnapshotParams) { + return this.activeSentioApi?.getUserScoreSnapshot(params); + } + /** * @experimental * Returns the current instance to allow method chaining. diff --git a/src/interface.ts b/src/interface.ts index 1d39ede..0c6a74e 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -66,7 +66,7 @@ export type WriteTransactionResponse = { }; export interface GraphQLResponse { - data: T; + result: T; errors?: { message: string }[]; } @@ -222,3 +222,48 @@ export interface UserInfo { closed: number; timestamp: string; } + +export interface GetUserScoreSnapshotParams { + userAddress: string; + blockDate: number; +} + +export interface SentioApiParams { + url: string; + apiKey: string; +} + +export interface GetUserScoreSnapshotResponse { + runtimeCost: string; + result: Result; + computeStats: ComputeStats; +} + +interface ComputeStats { + computedAt: string; + computeCostMs: string; + binaryVersionHash: string; + computedBy: string; + isCached: boolean; + isRefreshing: boolean; +} + +interface Result { + columns: string[]; + columnTypes: ColumnTypes; + rows: Row[]; + generatedAt: string; + cursor: string; +} + +export interface Row { + block_date: string; + total_value_locked_score: number; + tradeVolume: number; +} + +interface ColumnTypes { + block_date: string; + total_value_locked_score: string; + tradeVolume: string; +} diff --git a/src/query/index.ts b/src/query/indexerQuery.ts similarity index 100% rename from src/query/index.ts rename to src/query/indexerQuery.ts diff --git a/src/query/sentioQuery.ts b/src/query/sentioQuery.ts new file mode 100644 index 0000000..c7d99f1 --- /dev/null +++ b/src/query/sentioQuery.ts @@ -0,0 +1,56 @@ +import { + GetUserScoreSnapshotParams, + GetUserScoreSnapshotResponse, + SentioApiParams, +} from "src/interface"; +import { Fetch } from "src/utils/Fetch"; + +interface sqlQueryParams { + sqlQuery: { + sql: string; + size: number; + }; +} + +export class SentioQuery extends Fetch { + private apiKey: string; + + constructor({ url, apiKey }: SentioApiParams) { + super(url); + this.apiKey = apiKey; + } + + async getUserScoreSnapshotQuery({ + userAddress, + blockDate, + }: GetUserScoreSnapshotParams): Promise { + const sqlQuery: sqlQueryParams = { + sqlQuery: { + sql: `SELECT total_value_locked_score, tradeVolume, block_date FROM UserScoreSnapshot_raw WHERE user_address = '${userAddress}' AND timestamp > '${blockDate}' ORDER BY timestamp;`, + size: 1000, + }, + }; + const headers: Record = { + "api-key": this.apiKey, + }; + return await this.post( + sqlQuery, + "same-origin", + headers, + ); + } +} + +export const getUserScoreSnapshotQuery = async ({ + userAddress, + blockDate, + url, + apiKey, +}: GetUserScoreSnapshotParams & + SentioApiParams): Promise => { + const sentioQuery = new SentioQuery({ url, apiKey }); + return await sentioQuery.getUserScoreSnapshotQuery({ + userAddress, + blockDate, + }); +}; diff --git a/src/sentioApi.ts b/src/sentioApi.ts new file mode 100644 index 0000000..b58faef --- /dev/null +++ b/src/sentioApi.ts @@ -0,0 +1,21 @@ +import { getUserScoreSnapshotQuery } from "./query/sentioQuery"; +import { GetUserScoreSnapshotParams, SentioApiParams } from "./interface"; + +export class SentioApi { + private url: string; + private apiKey: string; + + constructor({ url, apiKey }: SentioApiParams) { + this.url = url; + this.apiKey = apiKey; + } + + getUserScoreSnapshot = (params: GetUserScoreSnapshotParams) => { + return getUserScoreSnapshotQuery({ + userAddress: params.userAddress, + blockDate: params.blockDate, + url: this.url, + apiKey: this.apiKey, + }); + }; +} diff --git a/src/utils/Fetch.ts b/src/utils/Fetch.ts index 0c16971..b73fb9a 100644 --- a/src/utils/Fetch.ts +++ b/src/utils/Fetch.ts @@ -1,4 +1,3 @@ -import { GraphQLResponse } from "src/interface"; import { Nilable } from "tsdef"; export class Fetch { @@ -14,18 +13,15 @@ export class Fetch { ): Promise => { return fetch(endpoint, data) .then((response) => response.json()) - .then((data: GraphQLResponse) => { - if (data.errors) { - throw new Error(data.errors[0].message); - } - - return data.data; + .then((data: T) => { + return data; }); }; protected post = ( body: Record, credentials: RequestCredentials = "same-origin", + headers: Record, ) => { return this.request(this.url, { method: "POST", @@ -33,6 +29,7 @@ export class Fetch { credentials, headers: { "Content-Type": "application/json", + ...headers, }, }); }; diff --git a/tests/indexerApi.test.ts b/tests/indexerApi.test.ts index f9f4e9c..df949c5 100644 --- a/tests/indexerApi.test.ts +++ b/tests/indexerApi.test.ts @@ -19,7 +19,10 @@ import { OrderType, TradeOrderEvent, } from "../src/interface"; -import { getActiveOrdersQuery, getOrdersQuery } from "../src/query"; +import { + getActiveOrdersQuery, + getOrdersQuery, +} from "../src/query/indexerQuery"; const USER_ADDRESS = "0x0000"; const ASSET_ADDRESS = "0x0001";