Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions api.apollo.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ApolloClient, ApolloLink, createHttpLink, InMemoryCache } from '@apollo/client/core';
import { onError } from '@apollo/client/link/error';
import fetch from 'cross-fetch';
import { CONFIG } from './api.config';

const errorLink = onError(({ graphQLErrors, networkError, operation }) => {
if (graphQLErrors) {
graphQLErrors.forEach((error) => {
console.error(`[GraphQL error in operation: ${operation?.operationName || 'unknown'}]`, {
message: error.message,
locations: error.locations,
path: error.path,
});
});
}
if (networkError) {
console.error(`[Network error in operation: ${operation?.operationName || 'unknown'}]`, {
message: networkError.message,
name: networkError.name,
stack: networkError.stack,
});
}
});

const httpLink = createHttpLink({
uri: CONFIG.indexer,
fetch: (uri: RequestInfo | URL, options?: RequestInit) => {
const controller = new AbortController();
const timeout = setTimeout(() => {
controller.abort();
}, 10000); // 10 second timeout

return fetch(uri, {
...options,
signal: controller.signal,
}).finally(() => {
clearTimeout(timeout);
});
},
});

const link = ApolloLink.from([errorLink, httpLink]);

export const PONDER_CLIENT = new ApolloClient({
link,
cache: new InMemoryCache(),
});
7 changes: 0 additions & 7 deletions api.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ApolloClient, InMemoryCache } from '@apollo/client/core';
import { Chain, createPublicClient, http } from 'viem';
import { mainnet, polygon } from 'viem/chains';

Expand Down Expand Up @@ -67,12 +66,6 @@ console.log(CONFIG);
// Refer to https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
process.env.NTBA_FIX_350 = 'true';

// PONDER CLIENT REQUEST
export const PONDER_CLIENT = new ApolloClient({
uri: CONFIG.indexer,
cache: new InMemoryCache(),
});

// VIEM CONFIG
export const VIEM_CHAIN = CONFIG.chain;
export const VIEM_CONFIG = createPublicClient({
Expand Down
93 changes: 63 additions & 30 deletions api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class ApiService {
private indexing: boolean = false;
private indexingTimeoutCount: number = 0;
private fetchedBlockheight: number = 0;
private isUpdatingWorkflow: boolean = false;

constructor(
private readonly minter: EcosystemMinterService,
Expand All @@ -41,45 +42,77 @@ export class ApiService {
}

async updateWorkflow() {
if (this.isUpdatingWorkflow) {
this.logger.warn(`Skipping updateWorkflow - previous update still in progress at block ${this.fetchedBlockheight}`);
return;
}

this.isUpdatingWorkflow = true;
this.logger.log(`Fetched blockheight: ${this.fetchedBlockheight}`);
const promises = [
this.minter.updateMinters(),
this.positions.updatePositonV2s(),
this.positions.updateMintingUpdateV2s(),
this.prices.updatePrices(),
this.stablecoin.updateEcosystemKeyValues(),
this.stablecoin.updateEcosystemMintBurnMapping(),
this.deps.updateDepsInfo(),
this.leadrate.updateLeadrateRates(),
this.leadrate.updateLeadrateProposals(),
this.challenges.updateChallengeV2s(),
this.challenges.updateBidV2s(),
this.challenges.updateChallengesPrices(),
this.savings.updateSavingsUserLeaderboard(),
];

return Promise.all(promises);
try {
const timeTask = async (name: string, fn: () => Promise<any>) => {
const start = Date.now();
try {
await fn();
this.logger.debug(`${name} completed in ${Date.now() - start}ms`);
} catch (err) {
this.logger.error(`Failed to update ${name} after ${Date.now() - start}ms:`, err);
throw err;
}
};

const promises = [
await timeTask('updateMinters', () => this.minter.updateMinters()).catch(() => {}),
await timeTask('updatePositonV2s', () => this.positions.updatePositonV2s()).catch(() => {}),
await timeTask('updateMintingUpdateV2s', () => this.positions.updateMintingUpdateV2s()).catch(() => {}),
await timeTask('updatePrices', () => this.prices.updatePrices()).catch(() => {}),
await timeTask('updateEcosystemKeyValues', () => this.stablecoin.updateEcosystemKeyValues()).catch(() => {}),
await timeTask('updateEcosystemMintBurnMapping', () => this.stablecoin.updateEcosystemMintBurnMapping()).catch(() => {}),
await timeTask('updateDepsInfo', () => this.deps.updateDepsInfo()).catch(() => {}),
await timeTask('updateLeadrateRates', () => this.leadrate.updateLeadrateRates()).catch(() => {}),
await timeTask('updateLeadrateProposals', () => this.leadrate.updateLeadrateProposals()).catch(() => {}),
await timeTask('updateChallengeV2s', () => this.challenges.updateChallengeV2s()).catch(() => {}),
await timeTask('updateBidV2s', () => this.challenges.updateBidV2s()).catch(() => {}),
await timeTask('updateChallengesPrices', () => this.challenges.updateChallengesPrices()).catch(() => {}),
await timeTask('updateSavingsUserLeaderboard', () => this.savings.updateSavingsUserLeaderboard()).catch(() => {}),
];

await Promise.all(promises);
} finally {
this.isUpdatingWorkflow = false;
}
}

async updateSocialMedia() {
this.socialMediaService.update();
this.socialMediaService.update().catch((err) => this.logger.error('Failed to update social media:', err));
}

@Interval(POLLING_DELAY[CONFIG.chain.id])
async updateBlockheight() {
const tmp: number = parseInt((await VIEM_CONFIG.getBlockNumber()).toString());
this.indexingTimeoutCount += 1;
if (tmp > this.fetchedBlockheight && !this.indexing) {
this.indexing = true;
await this.updateWorkflow();
await this.updateSocialMedia();
this.indexingTimeoutCount = 0;
this.fetchedBlockheight = tmp;
this.indexing = false;
}
if (this.indexingTimeoutCount >= INDEXING_TIMEOUT_COUNT && this.indexing) {
this.indexingTimeoutCount = 0;
this.indexing = false;
try {
const tmp: number = parseInt((await VIEM_CONFIG.getBlockNumber()).toString());
this.indexingTimeoutCount += 1;
if (tmp > this.fetchedBlockheight && !this.indexing) {
this.indexing = true;
try {
await this.updateWorkflow();
await this.updateSocialMedia();
this.indexingTimeoutCount = 0;
this.fetchedBlockheight = tmp;
} catch (error) {
this.logger.error('Error in updateWorkflow:', error);
} finally {
this.indexing = false;
}
}
if (this.indexingTimeoutCount >= INDEXING_TIMEOUT_COUNT && this.indexing) {
this.logger.warn(`Indexing timeout reached after ${INDEXING_TIMEOUT_COUNT} attempts`);
this.indexingTimeoutCount = 0;
this.indexing = false;
}
} catch (error) {
this.logger.error('Error getting block number:', error);
}
}
}
9 changes: 5 additions & 4 deletions bridge/bridge.service.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { gql } from '@apollo/client/core';
import { Injectable } from '@nestjs/common';
import { PONDER_CLIENT } from 'api.config';
import { PONDER_CLIENT } from 'api.apollo.config';
import { StablecoinBridgeQuery } from './bridge.types';

import { StablecoinEnum } from './bridge.enum';

@Injectable()
export class BridgeService {
async getBridgedStables(stablecoinParam: string, timestamp: Date): Promise<StablecoinBridgeQuery[]> {
const stablecoin = stablecoinParam.toUpperCase();
async getBridgedStables(stablecoin: StablecoinEnum, timestamp: Date): Promise<StablecoinBridgeQuery[]> {
const checkTimestamp = Math.trunc(timestamp.getTime() / 1000);

const bridgeFetched = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetBridge${stablecoin} {
bridge${stablecoin}s(
orderBy: "timestamp", orderDirection: "desc"
where: {
Expand Down
7 changes: 4 additions & 3 deletions challenges/challenges.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable, Logger } from '@nestjs/common';
import { gql } from '@apollo/client/core';
import { PONDER_CLIENT, VIEM_CONFIG } from 'api.config';
import { VIEM_CONFIG } from 'api.config';
import { PONDER_CLIENT } from 'api.apollo.config';
import {
ApiBidsBidders,
ApiBidsChallenges,
Expand Down Expand Up @@ -199,7 +200,7 @@ export class ChallengesService {
const challenges = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetChallengesV2 {
challengeV2s(orderBy: "status", orderDirection: "asc", limit: 1000) {
items {
id
Expand Down Expand Up @@ -244,7 +245,7 @@ export class ChallengesService {
const bids = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetChallengeBidsV2 {
challengeBidV2s(orderBy: "created", orderDirection: "desc", limit: 1000) {
items {
id
Expand Down
5 changes: 3 additions & 2 deletions ecosystem/ecosystem.deps.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { gql } from '@apollo/client/core';
import { ADDRESS, DecentralizedEUROABI, EquityABI } from '@deuro/eurocoin';
import { Injectable, Logger } from '@nestjs/common';
import { PONDER_CLIENT, VIEM_CONFIG } from 'api.config';
import { VIEM_CONFIG } from 'api.config';
import { PONDER_CLIENT } from 'api.apollo.config';
import { PositionsService } from 'positions/positions.service';
import { formatUnits } from 'viem';
import { ApiEcosystemDepsInfo } from './ecosystem.deps.types';
Expand Down Expand Up @@ -52,7 +53,7 @@ export class EcosystemDepsService {
const profitLossPonder = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetDEPS {
dEPSs(orderBy: "id", limit: 1000) {
items {
id
Expand Down
4 changes: 2 additions & 2 deletions ecosystem/ecosystem.minter.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable, Logger } from '@nestjs/common';
import { PONDER_CLIENT } from '../api.config';
import { PONDER_CLIENT } from '../api.apollo.config';
import { gql } from '@apollo/client/core';
import { ApiMinterListing, ApiMinterMapping, MinterQuery, MinterQueryObjectArray } from './ecosystem.minter.types';
import { Address } from 'viem';
Expand Down Expand Up @@ -31,7 +31,7 @@ export class EcosystemMinterService {
const { data } = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetMinters {
minters(orderBy: "id", limit: 1000) {
items {
id
Expand Down
7 changes: 4 additions & 3 deletions ecosystem/ecosystem.stablecoin.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { gql } from '@apollo/client/core';
import { ADDRESS } from '@deuro/eurocoin';
import { Injectable, Logger } from '@nestjs/common';
import { CONFIG, PONDER_CLIENT } from 'api.config';
import { PONDER_CLIENT } from 'api.apollo.config';
import { CONFIG } from 'api.config';
import { PricesService } from 'prices/prices.service';
import { Address } from 'viem';
import { EcosystemCollateralService } from './ecosystem.collateral.service';
Expand Down Expand Up @@ -72,7 +73,7 @@ export class EcosystemStablecoinService {
const ecosystem = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetEcosystems {
ecosystems(orderBy: "id", limit: 1000) {
items {
id
Expand Down Expand Up @@ -129,7 +130,7 @@ export class EcosystemStablecoinService {
const response = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetMintBurnAddressMappers {
mintBurnAddressMappers(orderBy: "id", limit: 1000) {
items {
id
Expand Down
6 changes: 3 additions & 3 deletions frontendcode/frontendcode.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { gql } from '@apollo/client/core';
import { Injectable } from '@nestjs/common';
import { PONDER_CLIENT } from 'api.config';
import { PONDER_CLIENT } from 'api.apollo.config';
import { FrontendCodeRegisteredQuery, FrontendCodeSavingsQuery } from './frontendcode.types';

@Injectable()
Expand All @@ -11,7 +11,7 @@ export class FrontendCodeService {
const frontendCodeFetched = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetFrontendCodeRegistered {
frontendCodeRegistereds(
orderBy: "created", orderDirection: "desc"
where: { created_gt: "${checkTimestamp}" }
Expand All @@ -35,7 +35,7 @@ export class FrontendCodeService {
const savedFetched = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetFrontendCodeSavingsSaved {
savingsSaveds(
orderBy: "created", orderDirection: "desc"
where: { created_gt: "${checkTimestamp}" }
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@types/node-telegram-bot-api": "^0.64.7",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cross-fetch": "^4.1.0",
"dotenv": "^16.3.1",
"graphql": "^16.8.2",
"node-telegram-bot-api": "^0.66.0",
Expand Down
7 changes: 4 additions & 3 deletions positions/positions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { ADDRESS, PositionV2ABI, SavingsABI } from '@deuro/eurocoin';
import { Injectable, Logger } from '@nestjs/common';
import { FIVEDAYS_MS } from 'utils/const-helper';
import { Address, erc20Abi, getAddress } from 'viem';
import { CONFIG, PONDER_CLIENT, VIEM_CONFIG } from '../api.config';
import { CONFIG, VIEM_CONFIG } from '../api.config';
import { PONDER_CLIENT } from '../api.apollo.config';
import {
ApiMintingUpdateListing,
ApiMintingUpdateMapping,
Expand Down Expand Up @@ -79,7 +80,7 @@ export class PositionsService {
const { data } = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetPositionsV2 {
positionV2s(orderBy: "availableForClones", orderDirection: "desc", limit: 1000) {
items {
position
Expand Down Expand Up @@ -270,7 +271,7 @@ export class PositionsService {
const { data } = await PONDER_CLIENT.query({
fetchPolicy: 'no-cache',
query: gql`
query {
query GetMintingUpdatesV2 {
mintingUpdateV2s(orderBy: "created", orderDirection: "desc", limit: 1000) {
items {
id
Expand Down
Loading