From ee6b723ba5bff3052c209f0d207ec9504750b7c6 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 31 Dec 2024 07:51:39 +0100 Subject: [PATCH 1/8] Feature/update OSS friends list 20241230 (#4166) * Update OSS friends list --- apps/client/src/assets/oss-friends.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/client/src/assets/oss-friends.json b/apps/client/src/assets/oss-friends.json index c3a127933..c7d1be3e9 100644 --- a/apps/client/src/assets/oss-friends.json +++ b/apps/client/src/assets/oss-friends.json @@ -1,6 +1,11 @@ { - "createdAt": "2024-11-27T00:00:00.000Z", + "createdAt": "2024-12-30T00:00:00.000Z", "data": [ + { + "name": "Activepieces", + "description": "Activepieces is an open source, no-code, AI-first business automation tool. Alternative to Zapier, Make and Workato.", + "href": "https://activepieces.com" + }, { "name": "Aptabase", "description": "Analytics for Apps, open source, simple and privacy-friendly. SDKs for Swift, React Native, Electron, Flutter and many others.", From aca4c3d46dce1169bf7cbe8542521dfb9d12e796 Mon Sep 17 00:00:00 2001 From: Lennart Goedhart Date: Tue, 31 Dec 2024 18:33:36 +1100 Subject: [PATCH 2/8] Feature/modernize docker compose files (#4101) * Modernize docker compose files * Update changelog --- .env.example | 4 +-- CHANGELOG.md | 4 +++ DEVELOPMENT.md | 2 +- README.md | 22 +++++++++++---- docker/docker-compose.build.yml | 49 +++++++-------------------------- docker/docker-compose.dev.yml | 17 ++++-------- docker/docker-compose.yml | 20 ++++++++------ 7 files changed, 51 insertions(+), 67 deletions(-) diff --git a/.env.example b/.env.example index 766894992..e4a935626 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,7 @@ COMPOSE_PROJECT_NAME=ghostfolio # CACHE -REDIS_HOST=localhost +REDIS_HOST=redis REDIS_PORT=6379 REDIS_PASSWORD= @@ -12,5 +12,5 @@ POSTGRES_PASSWORD= # VARIOUS ACCESS_TOKEN_SALT= -DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?connect_timeout=300&sslmode=prefer +DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?connect_timeout=300&sslmode=prefer JWT_SECRET_KEY= diff --git a/CHANGELOG.md b/CHANGELOG.md index aded12c46..1fbf59122 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Changed the `REDIS_HOST` from `localhost` to `redis` in `.env.example` +- Changed the _Postgres_ host from `localhost` to `postgres` in `.env.example` +- Changed the _Postgres_ image from `postgres:15` to `postgres:15-alpine` in the `docker-compose` files +- Introduced `extends` in the `docker-compose` files - Improved the language localization for German (`de`) ## 2.132.0 - 2024-12-30 diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index b009679ac..9e32b56eb 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -12,7 +12,7 @@ ### Setup 1. Run `npm install` -1. Run `docker compose --env-file ./.env -f docker/docker-compose.dev.yml up -d` to start [PostgreSQL](https://www.postgresql.org) and [Redis](https://redis.io) +1. Run `docker compose -f docker/docker-compose.dev.yml up -d` to start [PostgreSQL](https://www.postgresql.org) and [Redis](https://redis.io) 1. Run `npm run database:setup` to initialize the database schema 1. Start the [server](#start-server) and the [client](#start-client) 1. Open https://localhost:4200/en in your browser diff --git a/README.md b/README.md index dca360c39..4151617c8 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ We provide official container images hosted on [Docker Hub](https://hub.docker.c Run the following command to start the Docker images from [Docker Hub](https://hub.docker.com/r/ghostfolio/ghostfolio): ```bash -docker compose --env-file ./.env -f docker/docker-compose.yml up -d +docker compose -f docker/docker-compose.yml up -d ``` #### b. Build and run environment @@ -126,8 +126,8 @@ docker compose --env-file ./.env -f docker/docker-compose.yml up -d Run the following commands to build and start the Docker images: ```bash -docker compose --env-file ./.env -f docker/docker-compose.build.yml build -docker compose --env-file ./.env -f docker/docker-compose.build.yml up -d +docker compose -f docker/docker-compose.build.yml build +docker compose -f docker/docker-compose.build.yml up -d ``` #### Setup @@ -137,9 +137,19 @@ docker compose --env-file ./.env -f docker/docker-compose.build.yml up -d #### Upgrade Version -1. Increase the version of the `ghostfolio/ghostfolio` Docker image in `docker/docker-compose.yml` -1. Run the following command to start the new Docker image: `docker compose --env-file ./.env -f docker/docker-compose.yml up -d` - At each start, the container will automatically apply the database schema migrations if needed. +1. Update the _Ghostfolio_ Docker image + + - Increase the version of the `ghostfolio/ghostfolio` Docker image in `docker/docker-compose.yml` + - Run the following command if `ghostfolio:latest` is set: + ```bash + docker compose -f docker/docker-compose.yml pull + ``` + +1. Run the following command to start the new Docker image: + ```bash + docker compose -f docker/docker-compose.yml up -d + ``` + The container will automatically apply any required database schema migrations during startup. ### Home Server Systems (Community) diff --git a/docker/docker-compose.build.yml b/docker/docker-compose.build.yml index 96829ad34..a2b3e7cb4 100644 --- a/docker/docker-compose.build.yml +++ b/docker/docker-compose.build.yml @@ -2,51 +2,22 @@ name: ghostfolio_build services: ghostfolio: build: ../ - container_name: ghostfolio-build - init: true - env_file: - - ../.env - environment: - DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?connect_timeout=300&sslmode=prefer - REDIS_HOST: redis - REDIS_PASSWORD: ${REDIS_PASSWORD} - ports: - - 3333:3333 - depends_on: - postgres: - condition: service_healthy - redis: - condition: service_healthy - healthcheck: - test: ['CMD-SHELL', 'curl -f http://localhost:3333/api/v1/health'] - interval: 10s - timeout: 5s - retries: 5 + image: ghostfolio/ghostfolio:local + extends: + file: docker-compose.yml + service: ghostfolio postgres: - image: docker.io/library/postgres:15 container_name: gf-postgres-build - env_file: - - ../.env - healthcheck: - test: ['CMD-SHELL', 'pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}'] - interval: 10s - timeout: 5s - retries: 5 - volumes: - - postgres:/var/lib/postgresql/data + extends: + file: docker-compose.yml + service: postgres redis: - image: docker.io/library/redis:alpine container_name: gf-redis-build - env_file: - - ../.env - command: ['redis-server', '--requirepass', $REDIS_PASSWORD] - healthcheck: - test: ['CMD-SHELL', 'redis-cli --pass "$REDIS_PASSWORD" ping | grep PONG'] - interval: 10s - timeout: 5s - retries: 5 + extends: + file: docker-compose.yml + service: redis volumes: postgres: diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 39a1d56e9..ec91025ea 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -1,23 +1,18 @@ name: ghostfolio_dev services: postgres: - image: docker.io/library/postgres:15 + extends: + file: docker-compose.yml + service: postgres container_name: gf-postgres-dev - restart: unless-stopped - env_file: - - ../.env ports: - ${POSTGRES_PORT:-5432}:5432 - volumes: - - postgres:/var/lib/postgresql/data redis: - image: docker.io/library/redis:alpine + extends: + file: docker-compose.yml + service: redis container_name: gf-redis-dev - restart: unless-stopped - env_file: - - ../.env - command: ['redis-server', '--requirepass', $REDIS_PASSWORD] ports: - ${REDIS_PORT:-6379}:6379 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index c6ec5b3d7..8c69e5420 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -3,6 +3,7 @@ services: ghostfolio: image: docker.io/ghostfolio/ghostfolio:latest container_name: ghostfolio + restart: unless-stopped init: true cap_drop: - ALL @@ -10,10 +11,6 @@ services: - no-new-privileges:true env_file: - ../.env - environment: - DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?connect_timeout=300&sslmode=prefer - REDIS_HOST: redis - REDIS_PASSWORD: ${REDIS_PASSWORD} ports: - 3333:3333 depends_on: @@ -28,8 +25,9 @@ services: retries: 5 postgres: - image: docker.io/library/postgres:15 + image: docker.io/library/postgres:15-alpine container_name: gf-postgres + restart: unless-stopped cap_drop: - ALL cap_add: @@ -43,7 +41,8 @@ services: env_file: - ../.env healthcheck: - test: ['CMD-SHELL', 'pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}'] + test: + ['CMD-SHELL', 'pg_isready -d "$${POSTGRES_DB}" -U $${POSTGRES_USER}'] interval: 10s timeout: 5s retries: 5 @@ -53,6 +52,7 @@ services: redis: image: docker.io/library/redis:alpine container_name: gf-redis + restart: unless-stopped user: '999:1000' cap_drop: - ALL @@ -60,9 +60,13 @@ services: - no-new-privileges:true env_file: - ../.env - command: ['redis-server', '--requirepass', $REDIS_PASSWORD] + command: + - /bin/sh + - -c + - redis-server --requirepass "$${REDIS_PASSWORD:?REDIS_PASSWORD variable is not set}" healthcheck: - test: ['CMD-SHELL', 'redis-cli --pass "$REDIS_PASSWORD" ping | grep PONG'] + test: + ['CMD-SHELL', 'redis-cli --pass "$${REDIS_PASSWORD}" ping | grep PONG'] interval: 10s timeout: 5s retries: 5 From 7a602ea2d66d41a0d2a6de23355cdf7165d3efb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20=C5=81=C4=85giewka?= Date: Wed, 1 Jan 2025 09:16:40 +0100 Subject: [PATCH 3/8] Feature/remove got in favor of using fetch (#4154) * Remove got in favor of using fetch * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/info/info.service.ts | 21 +- apps/api/src/app/logo/logo.service.ts | 8 +- .../coingecko/coingecko.service.ts | 29 +- .../openfigi/openfigi.service.ts | 23 +- .../trackinsight/trackinsight.service.ts | 21 +- .../eod-historical-data.service.ts | 25 +- .../financial-modeling-prep.service.ts | 20 +- .../ghostfolio/ghostfolio.service.ts | 25 +- .../data-provider/manual/manual.service.ts | 12 +- .../rapid-api/rapid-api.service.ts | 8 +- package-lock.json | 296 +----------------- package.json | 1 - 13 files changed, 91 insertions(+), 399 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fbf59122..f7babf45d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Eliminated `got` in favor of using `fetch` - Changed the `REDIS_HOST` from `localhost` to `redis` in `.env.example` - Changed the _Postgres_ host from `localhost` to `postgres` in `.env.example` - Changed the _Postgres_ image from `postgres:15` to `postgres:15-alpine` in the `docker-compose` files diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index cd4035164..b61d44620 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -33,7 +33,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as cheerio from 'cheerio'; import { format, subDays } from 'date-fns'; -import got from 'got'; @Injectable() export class InfoService { @@ -155,16 +154,15 @@ export class InfoService { private async countDockerHubPulls(): Promise { try { - const { pull_count } = await got( + const { pull_count } = (await fetch( `https://hub.docker.com/v2/repositories/ghostfolio/ghostfolio`, { headers: { 'User-Agent': 'request' }, - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } - ).json(); + ).then((res) => res.json())) as { pull_count: number }; return pull_count; } catch (error) { @@ -176,12 +174,11 @@ export class InfoService { private async countGitHubContributors(): Promise { try { - const { body } = await got('https://github.com/ghostfolio/ghostfolio', { - // @ts-ignore + const body = await fetch('https://github.com/ghostfolio/ghostfolio', { signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) - }); + }).then((res) => res.text()); const $ = cheerio.load(body); @@ -199,16 +196,15 @@ export class InfoService { private async countGitHubStargazers(): Promise { try { - const { stargazers_count } = await got( + const { stargazers_count } = (await fetch( `https://api.github.com/repos/ghostfolio/ghostfolio`, { headers: { 'User-Agent': 'request' }, - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } - ).json(); + ).then((res) => res.json())) as { stargazers_count: number }; return stargazers_count; } catch (error) { @@ -323,7 +319,7 @@ export class InfoService { PROPERTY_BETTER_UPTIME_MONITOR_ID )) as string; - const { data } = await got( + const { data } = await fetch( `https://uptime.betterstack.com/api/v2/monitors/${monitorId}/sla?from=${format( subDays(new Date(), 90), DATE_FORMAT @@ -334,12 +330,11 @@ export class InfoService { 'API_KEY_BETTER_UPTIME' )}` }, - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } - ).json(); + ).then((res) => res.json()); return data.attributes.availability / 100; } catch (error) { diff --git a/apps/api/src/app/logo/logo.service.ts b/apps/api/src/app/logo/logo.service.ts index 759db2afb..584f50cab 100644 --- a/apps/api/src/app/logo/logo.service.ts +++ b/apps/api/src/app/logo/logo.service.ts @@ -4,7 +4,6 @@ import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; import { HttpException, Injectable } from '@nestjs/common'; import { DataSource } from '@prisma/client'; -import got from 'got'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; @Injectable() @@ -44,15 +43,16 @@ export class LogoService { } private getBuffer(aUrl: string) { - return got( + return fetch( `https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${aUrl}&size=64`, { headers: { 'User-Agent': 'request' }, - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } - ).buffer(); + ) + .then((res) => res.arrayBuffer()) + .then((buffer) => Buffer.from(buffer)); } } diff --git a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts index ddc04ffcd..30dbe0ae1 100644 --- a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts +++ b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts @@ -26,12 +26,11 @@ import { SymbolProfile } from '@prisma/client'; import { format, fromUnixTime, getUnixTime } from 'date-fns'; -import got, { Headers } from 'got'; @Injectable() export class CoinGeckoService implements DataProviderInterface { private readonly apiUrl: string; - private readonly headers: Headers = {}; + private readonly headers: HeadersInit = {}; public constructor( private readonly configurationService: ConfigurationService @@ -69,19 +68,18 @@ export class CoinGeckoService implements DataProviderInterface { }; try { - const { name } = await got(`${this.apiUrl}/coins/${symbol}`, { + const { name } = await fetch(`${this.apiUrl}/coins/${symbol}`, { headers: this.headers, - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) - }).json(); + }).then((res) => res.json()); response.name = name; } catch (error) { let message = error; - if (error?.code === 'ABORT_ERR') { + if (error?.name === 'AbortError') { message = `RequestError: The operation to get the asset profile for ${symbol} was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; @@ -114,7 +112,7 @@ export class CoinGeckoService implements DataProviderInterface { [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; }> { try { - const { prices } = await got( + const { prices } = await fetch( `${ this.apiUrl }/coins/${symbol}/market_chart/range?vs_currency=${DEFAULT_CURRENCY.toLowerCase()}&from=${getUnixTime( @@ -122,10 +120,9 @@ export class CoinGeckoService implements DataProviderInterface { )}&to=${getUnixTime(to)}`, { headers: this.headers, - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json()); const result: { [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; @@ -169,16 +166,15 @@ export class CoinGeckoService implements DataProviderInterface { } try { - const quotes = await got( + const quotes = await fetch( `${this.apiUrl}/simple/price?ids=${symbols.join( ',' )}&vs_currencies=${DEFAULT_CURRENCY.toLowerCase()}`, { headers: this.headers, - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json()); for (const symbol in quotes) { response[symbol] = { @@ -192,7 +188,7 @@ export class CoinGeckoService implements DataProviderInterface { } catch (error) { let message = error; - if (error?.code === 'ABORT_ERR') { + if (error?.name === 'AbortError') { message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; @@ -212,13 +208,12 @@ export class CoinGeckoService implements DataProviderInterface { let items: LookupItem[] = []; try { - const { coins } = await got(`${this.apiUrl}/search?query=${query}`, { + const { coins } = await fetch(`${this.apiUrl}/search?query=${query}`, { headers: this.headers, - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) - }).json(); + }).then((res) => res.json()); items = coins.map(({ id: symbol, name }) => { return { @@ -234,7 +229,7 @@ export class CoinGeckoService implements DataProviderInterface { } catch (error) { let message = error; - if (error?.code === 'ABORT_ERR') { + if (error?.name === 'AbortError') { message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; diff --git a/apps/api/src/services/data-provider/data-enhancer/openfigi/openfigi.service.ts b/apps/api/src/services/data-provider/data-enhancer/openfigi/openfigi.service.ts index 3efe7e40d..bb9d0606c 100644 --- a/apps/api/src/services/data-provider/data-enhancer/openfigi/openfigi.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/openfigi/openfigi.service.ts @@ -4,7 +4,6 @@ import { parseSymbol } from '@ghostfolio/common/helper'; import { Injectable } from '@nestjs/common'; import { SymbolProfile } from '@prisma/client'; -import got, { Headers } from 'got'; @Injectable() export class OpenFigiDataEnhancerService implements DataEnhancerInterface { @@ -32,7 +31,7 @@ export class OpenFigiDataEnhancerService implements DataEnhancerInterface { return response; } - const headers: Headers = {}; + const headers: HeadersInit = {}; const { exchange, ticker } = parseSymbol({ symbol, dataSource: response.dataSource @@ -43,14 +42,20 @@ export class OpenFigiDataEnhancerService implements DataEnhancerInterface { this.configurationService.get('API_KEY_OPEN_FIGI'); } - const mappings = await got - .post(`${OpenFigiDataEnhancerService.baseUrl}/v3/mapping`, { - headers, - json: [{ exchCode: exchange, idType: 'TICKER', idValue: ticker }], - // @ts-ignore + const mappings = (await fetch( + `${OpenFigiDataEnhancerService.baseUrl}/v3/mapping`, + { + body: JSON.stringify([ + { exchCode: exchange, idType: 'TICKER', idValue: ticker } + ]), + headers: { + 'Content-Type': 'application/json', + ...headers + }, + method: 'POST', signal: AbortSignal.timeout(requestTimeout) - }) - .json(); + } + ).then((res) => res.json())) as any[]; if (mappings?.length === 1 && mappings[0].data?.length === 1) { const { compositeFIGI, figi, shareClassFIGI } = mappings[0].data[0]; diff --git a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts index a4e695284..56b90082d 100644 --- a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts @@ -7,7 +7,6 @@ import { Sector } from '@ghostfolio/common/interfaces/sector.interface'; import { Injectable } from '@nestjs/common'; import { SymbolProfile } from '@prisma/client'; import { countries } from 'countries-list'; -import got from 'got'; @Injectable() export class TrackinsightDataEnhancerService implements DataEnhancerInterface { @@ -45,27 +44,25 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface { return response; } - const profile = await got( + const profile = await fetch( `${TrackinsightDataEnhancerService.baseUrl}/funds/${symbol}.json`, { - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } ) - .json() + .then((res) => res.json()) .catch(() => { - return got( + return fetch( `${TrackinsightDataEnhancerService.baseUrl}/funds/${ symbol.split('.')?.[0] }.json`, { - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } ) - .json() + .then((res) => res.json()) .catch(() => { return {}; }); @@ -77,29 +74,27 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface { response.isin = isin; } - const holdings = await got( + const holdings = await fetch( `${TrackinsightDataEnhancerService.baseUrl}/holdings/${symbol}.json`, { - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } ) - .json() + .then((res) => res.json()) .catch(() => { - return got( + return fetch( `${TrackinsightDataEnhancerService.baseUrl}/holdings/${ symbol.split('.')?.[0] }.json`, { - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } ) - .json() + .then((res) => res.json()) .catch(() => { return {}; }); diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts index 3ba8eb04f..e427a830a 100644 --- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts +++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts @@ -31,7 +31,6 @@ import { SymbolProfile } from '@prisma/client'; import { addDays, format, isSameDay, isToday } from 'date-fns'; -import got from 'got'; import { isNumber } from 'lodash'; @Injectable() @@ -95,7 +94,7 @@ export class EodHistoricalDataService implements DataProviderInterface { [date: string]: IDataProviderHistoricalResponse; } = {}; - const historicalResult = await got( + const historicalResult = await fetch( `${this.URL}/div/${symbol}?api_token=${ this.apiKey }&fmt=json&from=${format(from, DATE_FORMAT)}&to=${format( @@ -103,10 +102,9 @@ export class EodHistoricalDataService implements DataProviderInterface { DATE_FORMAT )}`, { - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json()); for (const { date, value } of historicalResult) { response[date] = { @@ -140,7 +138,7 @@ export class EodHistoricalDataService implements DataProviderInterface { symbol = this.convertToEodSymbol(symbol); try { - const response = await got( + const response = await fetch( `${this.URL}/eod/${symbol}?api_token=${ this.apiKey }&fmt=json&from=${format(from, DATE_FORMAT)}&to=${format( @@ -148,10 +146,9 @@ export class EodHistoricalDataService implements DataProviderInterface { DATE_FORMAT )}&period=${granularity}`, { - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json()); return response.reduce( (result, { adjusted_close, date }) => { @@ -205,15 +202,14 @@ export class EodHistoricalDataService implements DataProviderInterface { }); try { - const realTimeResponse = await got( + const realTimeResponse = await fetch( `${this.URL}/real-time/${eodHistoricalDataSymbols[0]}?api_token=${ this.apiKey }&fmt=json&s=${eodHistoricalDataSymbols.join(',')}`, { - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json()); const quotes: { close: number; @@ -286,7 +282,7 @@ export class EodHistoricalDataService implements DataProviderInterface { } catch (error) { let message = error; - if (error?.code === 'ABORT_ERR') { + if (error?.name === 'AbortError') { message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; @@ -400,15 +396,14 @@ export class EodHistoricalDataService implements DataProviderInterface { })[] = []; try { - const response = await got( + const response = await fetch( `${this.URL}/search/${aQuery}?api_token=${this.apiKey}`, { - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } - ).json(); + ).then((res) => res.json()); searchResult = response.map( ({ Code, Currency, Exchange, ISIN: isin, Name: name, Type }) => { @@ -431,7 +426,7 @@ export class EodHistoricalDataService implements DataProviderInterface { } catch (error) { let message = error; - if (error?.code === 'ABORT_ERR') { + if (error?.name === 'AbortError') { message = `RequestError: The operation to search for ${aQuery} was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts index 933af4802..ed55b3c2f 100644 --- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -21,7 +21,6 @@ import { import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import { format, isAfter, isBefore, isSameDay } from 'date-fns'; -import got from 'got'; @Injectable() export class FinancialModelingPrepService implements DataProviderInterface { @@ -72,13 +71,12 @@ export class FinancialModelingPrepService implements DataProviderInterface { [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; }> { try { - const { historical } = await got( + const { historical } = await fetch( `${this.URL}/historical-price-full/${symbol}?apikey=${this.apiKey}`, { - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json()); const result: { [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; @@ -124,13 +122,12 @@ export class FinancialModelingPrepService implements DataProviderInterface { } try { - const quotes = await got( + const quotes = await fetch( `${this.URL}/quote/${symbols.join(',')}?apikey=${this.apiKey}`, { - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json()); for (const { price, symbol } of quotes) { response[symbol] = { @@ -144,7 +141,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { } catch (error) { let message = error; - if (error?.code === 'ABORT_ERR') { + if (error?.name === 'AbortError') { message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; @@ -164,15 +161,14 @@ export class FinancialModelingPrepService implements DataProviderInterface { let items: LookupItem[] = []; try { - const result = await got( + const result = await fetch( `${this.URL}/search?query=${query}&apikey=${this.apiKey}`, { - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } - ).json(); + ).then((res) => res.json()); items = result.map(({ currency, name, symbol }) => { return { @@ -187,7 +183,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { } catch (error) { let message = error; - if (error?.code === 'ABORT_ERR') { + if (error?.name === 'AbortError') { message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; diff --git a/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts b/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts index b6e86949b..a674d479a 100644 --- a/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts +++ b/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts @@ -28,7 +28,6 @@ import { import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import { format } from 'date-fns'; -import got from 'got'; import { StatusCodes } from 'http-status-codes'; @Injectable() @@ -86,17 +85,16 @@ export class GhostfolioService implements DataProviderInterface { } = {}; try { - const { dividends } = await got( + const { dividends } = (await fetch( `${this.URL}/v2/data-providers/ghostfolio/dividends/${symbol}?from=${format(from, DATE_FORMAT)}&granularity=${granularity}&to=${format( to, DATE_FORMAT )}`, { headers: await this.getRequestHeaders(), - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json())) as DividendsResponse; response = dividends; } catch (error) { @@ -130,17 +128,16 @@ export class GhostfolioService implements DataProviderInterface { [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; }> { try { - const { historicalData } = await got( + const { historicalData } = (await fetch( `${this.URL}/v2/data-providers/ghostfolio/historical/${symbol}?from=${format(from, DATE_FORMAT)}&granularity=${granularity}&to=${format( to, DATE_FORMAT )}`, { headers: await this.getRequestHeaders(), - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json())) as HistoricalResponse; return { [symbol]: historicalData @@ -192,20 +189,19 @@ export class GhostfolioService implements DataProviderInterface { } try { - const { quotes } = await got( + const { quotes } = (await fetch( `${this.URL}/v2/data-providers/ghostfolio/quotes?symbols=${symbols.join(',')}`, { headers: await this.getRequestHeaders(), - // @ts-ignore signal: AbortSignal.timeout(requestTimeout) } - ).json(); + ).then((res) => res.json())) as QuotesResponse; response = quotes; } catch (error) { let message = error; - if (error.code === 'ABORT_ERR') { + if (error.name === 'AbortError') { message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; @@ -235,20 +231,19 @@ export class GhostfolioService implements DataProviderInterface { let searchResult: LookupResponse = { items: [] }; try { - searchResult = await got( + searchResult = (await fetch( `${this.URL}/v2/data-providers/ghostfolio/lookup?query=${query}`, { headers: await this.getRequestHeaders(), - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } - ).json(); + ).then((res) => res.json())) as LookupResponse; } catch (error) { let message = error; - if (error.code === 'ABORT_ERR') { + if (error.name === 'AbortError') { message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; diff --git a/apps/api/src/services/data-provider/manual/manual.service.ts b/apps/api/src/services/data-provider/manual/manual.service.ts index 3e98a9d77..9ba84d6d3 100644 --- a/apps/api/src/services/data-provider/manual/manual.service.ts +++ b/apps/api/src/services/data-provider/manual/manual.service.ts @@ -27,7 +27,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import * as cheerio from 'cheerio'; import { addDays, format, isBefore } from 'date-fns'; -import got, { Headers } from 'got'; import * as jsonpath from 'jsonpath'; @Injectable() @@ -276,23 +275,22 @@ export class ManualService implements DataProviderInterface { ): Promise { try { let locale = scraperConfiguration.locale; - const { body, headers } = await got(scraperConfiguration.url, { - headers: scraperConfiguration.headers as Headers, - // @ts-ignore + const response = await fetch(scraperConfiguration.url, { + headers: scraperConfiguration.headers as HeadersInit, signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) }); - if (headers['content-type'].includes('application/json')) { - const data = JSON.parse(body); + if (response.headers['content-type'].includes('application/json')) { + const data = await response.json(); const value = String( jsonpath.query(data, scraperConfiguration.selector)[0] ); return extractNumberFromString({ locale, value }); } else { - const $ = cheerio.load(body); + const $ = cheerio.load(await response.text()); if (!locale) { try { diff --git a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts index 08cc2ef05..4c9bb2717 100644 --- a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts +++ b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts @@ -20,7 +20,6 @@ import { import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import { format } from 'date-fns'; -import got from 'got'; @Injectable() export class RapidApiService implements DataProviderInterface { @@ -135,7 +134,7 @@ export class RapidApiService implements DataProviderInterface { oneYearAgo: { value: number; valueText: string }; }> { try { - const { fgi } = await got( + const { fgi } = await fetch( `https://fear-and-greed-index.p.rapidapi.com/v1/fgi`, { headers: { @@ -143,18 +142,17 @@ export class RapidApiService implements DataProviderInterface { 'x-rapidapi-host': 'fear-and-greed-index.p.rapidapi.com', 'x-rapidapi-key': this.configurationService.get('API_KEY_RAPID_API') }, - // @ts-ignore signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) } - ).json(); + ).then((res) => res.json()); return fgi; } catch (error) { let message = error; - if (error?.code === 'ABORT_ERR') { + if (error?.name === 'AbortError') { message = `RequestError: The operation was aborted because the request to the data provider took more than ${( this.configurationService.get('REQUEST_TIMEOUT') / 1000 ).toFixed(3)} seconds`; diff --git a/package-lock.json b/package-lock.json index 305bcb27c..93189ca14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,6 @@ "date-fns": "3.6.0", "envalid": "7.3.1", "google-spreadsheet": "3.2.0", - "got": "11.8.6", "helmet": "7.0.0", "http-status-codes": "2.3.0", "ionicons": "7.4.0", @@ -9561,18 +9560,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", @@ -10643,18 +10630,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@testing-library/dom": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", @@ -11148,33 +11123,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "license": "MIT", - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/cacheable-request/node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/cacheable-request/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "license": "MIT" - }, "node_modules/@types/color": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/color/-/color-3.0.6.tgz", @@ -11418,12 +11366,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "license": "MIT" - }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", @@ -11558,30 +11500,6 @@ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "license": "MIT" }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/keyv/node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/keyv/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "license": "MIT" - }, "node_modules/@types/lodash": { "version": "4.17.7", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", @@ -11826,30 +11744,6 @@ "@types/react": "^18.0.0" } }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/responselike/node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/responselike/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "license": "MIT" - }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", @@ -14422,33 +14316,6 @@ "node": ">= 18" } }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "license": "MIT", - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cachedir": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", @@ -15058,27 +14925,6 @@ "node": ">=0.10.0" } }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone-response/node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", @@ -16881,21 +16727,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -16984,15 +16815,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -17531,6 +17353,7 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -19943,6 +19766,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, "license": "MIT", "dependencies": { "pump": "^3.0.0" @@ -20266,31 +20090,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -20786,6 +20585,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/http-deceiver": { @@ -20937,19 +20737,6 @@ "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", "license": "MIT" }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "license": "MIT", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -23281,6 +23068,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -23521,6 +23309,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -24746,15 +24535,6 @@ "devOptional": true, "license": "0BSD" }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -25600,18 +25380,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -26361,18 +26129,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/npm-bundled": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-4.0.0.tgz", @@ -26888,6 +26644,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -27036,15 +26793,6 @@ "dev": true, "license": "MIT" }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -28662,6 +28410,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -28759,18 +28508,6 @@ ], "license": "MIT" }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/rambda": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/rambda/-/rambda-9.4.1.tgz", @@ -29368,12 +29105,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "license": "MIT" - }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -29443,18 +29174,6 @@ "node": ">=10" } }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "license": "MIT", - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -34053,6 +33772,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "devOptional": true, "license": "ISC" }, "node_modules/write-file-atomic": { diff --git a/package.json b/package.json index 650918efd..607ec233b 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,6 @@ "date-fns": "3.6.0", "envalid": "7.3.1", "google-spreadsheet": "3.2.0", - "got": "11.8.6", "helmet": "7.0.0", "http-status-codes": "2.3.0", "ionicons": "7.4.0", From b9917e72b2ae6c9dfa9c3cdcd9bc556c8141eb34 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 1 Jan 2025 09:19:31 +0100 Subject: [PATCH 4/8] Feature/update year to 2025 (#4169) * Update year --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4151617c8..14477ea9a 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,6 @@ If you like to support this project, get [**Ghostfolio Premium**](https://ghostf ## License -© 2021 - 2024 [Ghostfolio](https://ghostfol.io) +© 2021 - 2025 [Ghostfolio](https://ghostfol.io) Licensed under the [AGPLv3 License](https://www.gnu.org/licenses/agpl-3.0.html). From 1cf7ffdee8aa78c77b75c8f1069ccf0bcf580e09 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:20:27 +0100 Subject: [PATCH 5/8] Feature/refresh cryptocurrencies list 20241230 (#4165) * Update cryptocurrencies.json * Update changelog --- CHANGELOG.md | 1 + .../cryptocurrencies/cryptocurrencies.json | 211 +++++++++++++++--- 2 files changed, 183 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7babf45d..4aa7a13b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed the _Postgres_ image from `postgres:15` to `postgres:15-alpine` in the `docker-compose` files - Introduced `extends` in the `docker-compose` files - Improved the language localization for German (`de`) +- Refreshed the cryptocurrencies list ## 2.132.0 - 2024-12-30 diff --git a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json index ac2157389..f77297d07 100644 --- a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json +++ b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json @@ -11,7 +11,7 @@ "611": "SixEleven", "777": "Jackpot", "808": "808", - "888": "Octocoin", + "888": "888", "1337": "EliteCoin", "1717": "1717 Masonic Commemorative Token", "2015": "2015 coin", @@ -26,6 +26,7 @@ "0DOG": "Bitcoin Dogs", "0KN": "0 Knowledge Network", "0NE": "Stone", + "0X0": "0x0.ai", "0X1": "0x1.tools: AI Multi-tool Plaform", "0XBTC": "0xBitcoin", "0XCOCO": "0xCoco", @@ -36,7 +37,6 @@ "0XOS": "0xOS AI", "0XSEARCH": "Search", "0XVOX": "HashVox AI", - "0x0": "0x0.ai", "0xDIARY": "The 0xDiary Token", "0xVPN": "0xVPN.org", "1-UP": "1-UP", @@ -50,6 +50,7 @@ "1EX": "1ex Trading Board", "1FLR": "Flare Token", "1GOLD": "1irstGold", + "1GUY": "1GUY", "1INCH": "1inch", "1IRST": "1irstcoin", "1MCT": "MicroCreditToken", @@ -136,6 +137,7 @@ "A8": "Ancient8", "AA": "Alva", "AAA": "Moon Rabbit", + "AAAHHM": "Plankton in Pain", "AAB": "AAX Token", "AABL": "Abble", "AAC": "Double-A Chain", @@ -177,6 +179,7 @@ "ABONDV1": "ApeSwap", "ABR": "Allbridge", "ABT": "ArcBlock", + "ABTC": "aBTC", "ABUL": "Abulaba", "ABUNI": "Uniswap Protocol Token (Arbitrum Bridge)", "ABUSDC": "USD Coin (Arbitrum Bridge)", @@ -318,6 +321,7 @@ "AGB": "Apes Go Bananas", "AGC": "Argocoin", "AGENT": "AgentLayer", + "AGENTFUN": "AgentFun.AI", "AGET": "Agetron", "AGETH": "Kelp Gain", "AGEUR": "agEUR", @@ -454,6 +458,7 @@ "AKRO": "Akropolis", "AKT": "Akash Network", "AKTIO": "AKTIO Coin", + "AKUMA": "Akuma Inu", "AL": "ArchLoot", "ALA": "Alanyaspor Fan Token", "ALAN": "Alan the Alien", @@ -502,6 +507,7 @@ "ALLC": "All Crypto Mechanics", "ALLEY": "NFT Alley", "ALLIN": "All in", + "ALLMEE": "All.me", "ALM": "Alium Finance", "ALMAN": "Alman", "ALMC": "Awkward Look Monkey Club", @@ -577,6 +583,7 @@ "AMO": "AMO Coin", "AMOGUS": "Sussy Baka Impostor", "AMON": "AmonD", + "AMORE": "Amocucinare", "AMOS": "Amos", "AMP": "Amp", "AMPL": "Ampleforth", @@ -736,7 +743,7 @@ "ARBS": "Arbswap", "ARBT": "ARBITRAGE", "ARBUZ": "ARBUZ", - "ARC": "Neko Arc", + "ARC": "Arc", "ARCA": "Legend of Arcadia", "ARCAD": "Arcadeum", "ARCADE": "ARCADE", @@ -818,6 +825,7 @@ "ARTFI": "ARTFI", "ARTG": "Goya Giant Token", "ARTH": "ARTH", + "ARTHERA": "Arthera", "ARTI": "Arti Project", "ARTIF": "Artificial Intelligence", "ARTII": "ARTII Token", @@ -906,6 +914,7 @@ "ATHE": "Atheios", "ATHEN": "Athenas AI", "ATHENA": "Athena DexFi", + "ATHER": "Ather", "ATHVODKA": "All Time High Vodka", "ATID": "AstridDAO Token", "ATK": "Attack Wagon", @@ -932,11 +941,12 @@ "ATOZ": "Race Kingdom", "ATP": "Atlas Protocol", "ATPAY": "AtPay", - "ATR": "Ather", + "ATR": "Artrade", "ATRI": "Atari Token", "ATRNO": "AETERNUS", "ATROFA": "Atrofarm", "ATRS": "Attarius Network", + "ATRV1": "Artrade v1", "ATS": "Atlas DEX", "ATT": "Attila", "ATTR": "Attrace", @@ -991,6 +1001,7 @@ "AVATAR": "Avatar", "AVATLY": "Avatly", "AVAV": "AVAV", + "AVAV1": "AVA v1", "AVAX": "Avalanche", "AVAXIOU": "Avalanche IOU", "AVB": "Autonomous Virtual Beings", @@ -1210,10 +1221,11 @@ "BAMBIT": "BAMBIT", "BAMBOO": "BambooDeFi", "BAMITCOIN": "Bamit", - "BAN": "Banano", + "BAN": "Comedian", "BANANA": "Banana Gun", "BANANAF": "Banana For Scale", "BANANAS": "Monkey Peepo", + "BANANO": "Banano", "BANC": "Babes and Nerds", "BANCA": "BANCA", "BAND": "Band Protocol", @@ -1455,6 +1467,7 @@ "BEPR": "Blockchain Euro Project", "BEPRO": "BEPRO Network", "BERF": "BERF", + "BERG": "Bloxberg", "BERN": "BERNcash", "BERNIE": "BERNIE SENDERS", "BERRY": "Berry", @@ -1873,6 +1886,7 @@ "BOBE": "BOOK OF BILLIONAIRES", "BOBER": "BOBER", "BOBFUN": "BOB", + "BOBLS": "Boblles", "BOBO": "BOBO", "BOBOT": "Bobo The Bear", "BOBS": "Bob's Repair", @@ -2217,6 +2231,7 @@ "BTCAS": "BitcoinAsia", "BTCAT": "Bitcoin Cat", "BTCB": "Bitcoin BEP2", + "BTCBASE": "Bitcoin on Base", "BTCBR": "Bitcoin BR", "BTCBRV1": "Bitcoin BR v1", "BTCC": "Bitcoin Core", @@ -2308,8 +2323,10 @@ "BUB": "BUBCAT", "BUBBA": "Bubba", "BUBBLE": "Bubble", + "BUBBLES": "BUBBLES", "BUBO": "Budbo", "BUBU": "BUBU", + "BUBV1": "BUBCAT v1", "BUC": "Beau Cat", "BUCK": "Coinbuck", "BUCKS": "SwagBucks", @@ -2784,7 +2801,9 @@ "CHEDDA": "Chedda", "CHEEKS": "CHEEKS", "CHEEL": "Cheelee", - "CHEEMS": "Cheems", + "CHEEMS": "Cheems (cheems.pet)", + "CHEEMSCO": "Cheems", + "CHEEMSV1": "Cheems (cheems.pet) v1", "CHEEPEPE": "CHEEPEPE", "CHEERS": "DICAPRIO CHEERS", "CHEESE": "Cheese", @@ -3107,7 +3126,7 @@ "COMFI": "CompliFi", "COMM": "Community Coin", "COMMUNITYCOIN": "Community Coin", - "COMP": "Compound Governance Token", + "COMP": "Compound", "COMPCOIN": "Compcoin", "COMPD": "Compound Coin", "COMPU": "Compute Network", @@ -3125,6 +3144,7 @@ "CONSENTIUM": "Consentium", "CONTROL": "Control Token", "CONV": "Convergence", + "CONVO": "Prefrontal Cortex Convo Agent by Virtuals", "CONX": "Connex", "COO": "Cool Cats MILK", "COOCHIE": "Cucci", @@ -3708,6 +3728,7 @@ "DCCT": "DocuChain", "DCD": "DecideAI", "DCE": "Decentra Ecosystem", + "DCF": "Decentralized Finance", "DCHEFSOL": "Degen Chef", "DCHEWY": "Drop Chewy", "DCHF": "DeFi Franc", @@ -3792,7 +3813,9 @@ "DEFY": "DEFY", "DEG": "Degis", "DEGA": "Dega", + "DEGATE": "DeGate", "DEGEN": "Degen", + "DEGENAI": "Degen Spartan AI", "DEGENR": "DegenReborn", "DEGO": "Dego Finance", "DEGOD": "degod", @@ -3802,6 +3825,7 @@ "DEI": "Deimos", "DEK": "DekBox", "DEL": "Decimal", + "DELAY": "DegenLayer", "DELCHAIN": "DelChain", "DELFI": "DeltaFi", "DELI": "NFTDeli", @@ -3914,6 +3938,7 @@ "DGPT": "DigiPulse", "DGTA": "Digitra.com Token", "DGTX": "Digitex Token", + "DGV1": "Decentral Games v1", "DGVC": "DegenVC", "DGX": "Digix Gold token", "DHLT": "DeHealth", @@ -4008,6 +4033,7 @@ "DKEY": "DKEY Bank", "DKKT": "DKK Token", "DKNIGHT": "Dark Knight", + "DKP": "Dragginz", "DKS": "DarkShield", "DKT": "Duelist King", "DKUMA": "KumaDex Token", @@ -4074,6 +4100,7 @@ "DOBBY": "Dobby", "DOBEN": "dark boden", "DOBO": "DogeBonk", + "DOBUY": "Just do buy", "DOC": "Dochain", "DOCAINEURON": "Doc.ai Neuron", "DOCC": "Doc Coin", @@ -4291,13 +4318,15 @@ "DRM8": "Dream8Coin", "DROGGY": "Droggy", "DRONE": "Drone Coin", - "DROP": "Dropil", + "DROP": "DROP", + "DROPIL": "Dropil", "DROPS": "Drops", "DROVERS": "Drover Inu", "DRP": "DCORP", "DRPU": "DRP Utility", "DRS": "Digital Rupees", "DRT": "DomRaider", + "DRUGS": "Big Pharmai", "DRXNE": "Droxne", "DRZ": "Droidz", "DS": "DeStorage", @@ -4486,6 +4515,7 @@ "EBEN": "Green Ben", "EBET": "EthBet", "EBIT": "eBit", + "EBITCOIN": "eBitcoin", "EBK": "Ebakus", "EBOX": "Ethbox Token", "EBS": "EbolaShare", @@ -4494,7 +4524,7 @@ "EBSO": "eBlockStock", "EBST": "eBoost", "EBT": "ELON BUYS TWITTER", - "EBTC": "eBitcoin", + "EBTC": "Ether.fi Staked BTC", "EBULL": "ETHEREUM IS GOOD", "EBYT": "EarthByt", "EBZ": "Ebitz", @@ -4680,6 +4710,7 @@ "ELONMU": "Elon Musk", "ELONONE": "AstroElon", "ELONPEPE": "Elon Pepe Robot", + "ELONRWA": "ElonRWA", "ELONTRUMP": "ELON TRUMP", "ELP": "Ellerium", "ELS": "Ethlas", @@ -4693,6 +4724,7 @@ "ELVN": "11Minutes", "ELX": "Energy Ledger", "ELY": "Elysian", + "ELYS": "Elys Network", "ELYSIUM": "Elysium", "EM": "Eminer", "EMAID": "MaidSafeCoin", @@ -4783,6 +4815,7 @@ "EOX": "EXTRA ORDINARY", "EPAN": "Paypolitan Token", "EPANUS": "Epanus", + "EPENDLE": "Equilibria Pendle", "EPEP": "Epep", "EPETS": "Etherpets", "EPIC": "Epic Cash", @@ -4891,7 +4924,7 @@ "ETHERDELTA": "EtherDelta", "ETHERE": "Ethereal", "ETHEREM": "Etherempires", - "ETHEREUM": "Solana Ethereum Meme", + "ETHEREUMMEME": "Solana Ethereum Meme", "ETHEREUMP": "ETHEREUMPLUS", "ETHERINC": "EtherInc", "ETHERKING": "Ether Kingdoms Token", @@ -4926,6 +4959,7 @@ "ETM": "En-Tan-Mo", "ETN": "Electroneum", "ETNA": "ETNA Network", + "ETNY": "Ethernity", "ETP": "Metaverse", "ETPOS": "EtherPOS", "ETR": "Electric Token", @@ -5056,6 +5090,7 @@ "EZT": "EZToken", "EZY": "EzyStayz", "ElvishMagic": "EMAGIC", + "F": "SynFutures", "F16": "F16Coin", "F1C": "Future1coin", "F2C": "Ftribe Fighters", @@ -5114,6 +5149,7 @@ "FAST": "Fastswap", "FASTAI": "Fast And Ai", "FASTMOON": "FastMoon", + "FASTUSD": "Sei fastUSD", "FASTV1": "Fastswap v1", "FAT": "Fatcoin", "FATCAKE": "FatCake", @@ -5153,6 +5189,7 @@ "FCS": "CryptoFocus", "FCT": "FirmaChain", "FCTC": "FaucetCoin", + "FCTR": "FactorDAO", "FDC": "Fidance", "FDLS": "FIDELIS", "FDM": "Fandom", @@ -5335,10 +5372,14 @@ "FLOKINY": "Floki New Year", "FLOKIPEPE": "FlokiPepe", "FLOKITA": "FLOKITA", + "FLOKIV1": "Floki v1", + "FLOKIV2": "Floki v2", + "FLOKIV3": "Floki v3", "FLOKIX": "FLOKI X", "FLOOF": "FLOOF", "FLOOR": "FloorDAO", "FLOP": "Big Floppa", + "FLOPPA": "Floppa Cat", "FLORK": "FLORK BNB", "FLORKY": "Florky", "FLOSHIDO": "FLOSHIDO INU", @@ -5491,8 +5532,9 @@ "FREAK": "Freakoff", "FREC": "Freyrchain", "FRECNX": "FreldoCoinX", - "FRED": "FREDEnergy", + "FRED": "First Convicted Raccon Fred", "FREDDY": "FREDDY", + "FREDE": "FREDEnergy", "FREE": "FREE coin", "FREED": "FreedomCoin", "FREEDO": "Freedom", @@ -5648,6 +5690,7 @@ "FXDX": "FXDX", "FXF": "Finxflo", "FXI": "FX1 Sports", + "FXN": "FXN", "FXP": "FXPay", "FXS": "Frax Share", "FXST": "FX Stock Token", @@ -5691,6 +5734,7 @@ "GALO": "Clube Atlético Mineiro Fan Token", "GALT": "Galtcoin", "GAM": "Gambit coin", + "GAMA": "GAMA Coin", "GAMB": "GAMB", "GAMBI": "Gambi Fi", "GAMBIT": "Gambit", @@ -5952,6 +5996,7 @@ "GKI": "GKi", "GL": "Lemmings", "GLA": "Gladius", + "GLASS": "Glass Chain", "GLAX": "BLOCK GALAXY NETWORK", "GLAZE": "Glaze", "GLB": "Golden Ball", @@ -5985,7 +6030,7 @@ "GLOWSHA": "GlowShares", "GLQ": "GraphLinq Protocol", "GLR": "Glory Finance", - "GLS": "Glass Chain", + "GLS": "Glacier", "GLT": "GlobalToken", "GLX": "GalaxyCoin", "GLYPH": "GlyphCoin", @@ -6196,6 +6241,8 @@ "GRID": "Grid+", "GRIDCOIN": "GridCoin", "GRIDZ": "GridZone.io", + "GRIFFAIN": "GRIFFAIN", + "GRIFT": "ORBIT", "GRIM": "GRIMREAPER", "GRIMACE": "Grimace", "GRIMEVO": "Grim EVO", @@ -6294,6 +6341,7 @@ "GTX": "GALLACTIC", "GUA": "GUA", "GUAC": "Guacamole", + "GUAN": "Guanciale by Virtuals", "GUAP": "Guapcoin", "GUAR": "Guarium", "GUARD": "Guardian", @@ -6316,6 +6364,7 @@ "GUP": "Guppy", "GURL": "Gently Used Girl", "GURU": "Guru Network", + "GUS": "Gus", "GUSD": "Gemini Dollar", "GUSDT": "Global Utility Smart Digital Token", "GUT": "Genesis Universe", @@ -6409,6 +6458,7 @@ "HARRIS": "KAMALA HARRIS", "HARRISV": "Harris V Trump", "HARRYP": "HarryPotterObamaSonic10Inu (ERC20)", + "HARRYPO": "HarryPotterObamaPacMan8Inu", "HART": "HARA", "HASBIK": "Hasbulla", "HASH": "Provenance Blockchain", @@ -6503,6 +6553,8 @@ "HERBE": "Herbee", "HERME": "Hermes DAO", "HERMES": "Hermes Protocol", + "HERMIONE": "Hermione", + "HERMY": "Hermy The Stallion", "HERO": "Metahero", "HEROC": "HEROcoin", "HEROES": "Dehero Community Token", @@ -6808,13 +6860,15 @@ "HYN": "Hyperion", "HYP": "HyperStake", "HYPC": "HyperCycle", - "HYPE": "Hype", + "HYPE": "Hyperliquid", "HYPER": "HyperChainX", "HYPERAI": "HyperHash AI", "HYPERCOIN": "HyperCoin", "HYPERD": "HyperDAO", + "HYPERIONX": "HyperionX", "HYPERS": "HyperSpace", "HYPES": "Supreme Finance", + "HYPEV1": "Hype v1", "HYPR": "Hypr Network", "HYS": "Heiss Shares", "HYT": "HoryouToken", @@ -6955,6 +7009,7 @@ "IMI": "Influencer", "IML": "IMMLA", "IMMO": "ImmortalDAO Finance", + "IMMORTAL": "IMMORTAL.COM", "IMO": "IMO", "IMP": "CoinIMP", "IMPACT": "Impact", @@ -6980,6 +7035,7 @@ "INCAKE": "InfinityCAKE", "INCEPT": "Incept", "INCNT": "Incent", + "INCO": "InfinitiCoin", "INCORGNITO": "Incorgnito", "INCP": "InceptionCoin", "IND": "Indorse", @@ -7208,6 +7264,7 @@ "JANE": "JaneCoin", "JANET": "Janet", "JANI": "JANI", + "JANRO": "Janro The Rat", "JAR": "Jarvis+", "JARED": "Jared From Subway", "JARY": "JeromeAndGary", @@ -7261,6 +7318,7 @@ "JFI": "JackPool.finance", "JFIN": "JFIN Coin", "JFIVE": "Jonny Five", + "JFP": "JUSTICE FOR PEANUT", "JGLP": "Jones GLP", "JGN": "Juggernaut", "JHH": "Jen-Hsun Huang", @@ -7430,6 +7488,7 @@ "KANGAL": "Kangal", "KANGO": "KANGO", "KAP": "KAP Games", + "KAPPY": "Kappy", "KAPU": "Kapu", "KAR": "Karura", "KARA": "KarateCat", @@ -7540,6 +7599,7 @@ "KI": "Genopets KI", "KIAN": "Porta", "KIBA": "Kiba Inu", + "KIBAV1": "Kiba Inu v1", "KIBSHI": "KiboShib", "KICK": "Kick", "KICKS": "GetKicks", @@ -7787,6 +7847,7 @@ "KWAI": "KWAI", "KWATT": "4New", "KWD": "KIWI DEFI", + "KWEEN": "KWEEN", "KWENTA": "Kwenta", "KWH": "KWHCoin", "KWIK": "KwikSwap", @@ -7799,6 +7860,7 @@ "KYL": "Kylin Network", "KYOKO": "Kyoko", "KYRA": "KYRA", + "KYSOL": "Kyros Restaked SOL", "KYTE": "Kambria Yield Tuning Engine", "KYUB": "Kyuubi", "KYVE": "KYVE Network", @@ -7843,6 +7905,7 @@ "LANDLORD": "LANDLORD RONALD", "LANDS": "Two Lands", "LANDV1": "Landshare v1", + "LANDW": "LandWolf", "LANDWOLF": "LANDWOLF", "LANDWOLFETH": "Landwolf", "LANDWU": "LandWu", @@ -7892,6 +7955,7 @@ "LC": "Lotus Capital", "LC4": "LEOcoin", "LCASH": "LitecoinCash", + "LCAT": "Lion Cat", "LCC": "LitecoinCash", "LCD": "Lucidao", "LCG": "LCG", @@ -7955,6 +8019,7 @@ "LEPEN": "LePenCoin", "LEPER": "Leper", "LESBIAN": "Lesbian Inu", + "LESLIE": "Leslie", "LESS": "Less Network", "LESSF": "LessFnGas", "LESTER": "Litecoin Mascot", @@ -7976,6 +8041,7 @@ "LEZGI": "LEZGI Token", "LF": "Linkflow", "LFC": "BigLifeCoin", + "LFDOG": "lifedog", "LFG": "Gamerse", "LFGO": "Lets Fuckin Go", "LFI": "LunaFi", @@ -8024,6 +8090,7 @@ "LIFT": "Uplift", "LIGER": "Ligercoin", "LIGHT": "LightChain", + "LIGHTSPEED": "LightSpeedCoin", "LIGMA": "Ligma Node", "LIGO": "Ligo", "LIKE": "Only1", @@ -8044,6 +8111,7 @@ "LINDACEO": "LindaYacc Ceo", "LINEA": "Linea", "LING": "Lingose", + "LINGO": "Lingo", "LINK": "Chainlink", "LINKA": "LINKA", "LINKC": "LINKCHAIN", @@ -8229,7 +8297,7 @@ "LRT": "LandRocker", "LRT2": "LRT Squared", "LSC": "LS Coin", - "LSD": "LightSpeedCoin", + "LSD": "Pontem Liquidswap", "LSDOGE": "LSDoge", "LSETH": "Liquid Staked ETH", "LSHARE": "LSHARE", @@ -8246,6 +8314,7 @@ "LSWAP": "LoopSwap", "LT": "Loctite Assets Token", "LTA": "Litra", + "LTAI": "LibertAI", "LTB": "Litebar", "LTBC": "LTBCoin", "LTBTC": "Lightning Bitcoin", @@ -8370,6 +8439,7 @@ "M": "MetaVerse-M", "M1": "SupplyShock", "M2O": "M2O Token", + "M3M3": "M3M3", "M87": "MESSIER", "MAAL": "Maal Chain", "MABA": "Make America Based Again", @@ -8467,6 +8537,7 @@ "MARIO": "MARIO CEO", "MARK": "Benchmark Protocol", "MARKE": "Market Ledger", + "MARKETMOVE": "MarketMove", "MARLEY": "Marley Token", "MARMAJ": "marmaj", "MARO": "Maro", @@ -8636,7 +8707,7 @@ "MDUS": "MEDIEUS", "MDX": "Mdex (BSC)", "MDXH": "Mdex (HECO)", - "ME": "All.me", + "ME": "Magic Eden", "MEAN": "Meanfi", "MEB": "Meblox Protocol", "MEC": "MegaCoin", @@ -8743,6 +8814,7 @@ "METAD": "MetaDoge", "METADIUM": "Metadium", "METADOGE": "MetaDoge", + "METADOGEV1": "MetaDoge V1", "METADOGEV2": "MetaDoge V2", "METAF": "MetaFastest", "METAG": "MetagamZ", @@ -8845,6 +8917,7 @@ "MIDAS": "Midas", "MIDASDOLLAR": "Midas Dollar Share", "MIDN": "Midnight", + "MIDNIGHT": "Midnight", "MIE": "MIE Network", "MIF": "monkeywifhat", "MIG": "Migranet", @@ -9111,6 +9184,7 @@ "MONAV": "Monavale", "MONB": "MonbaseCoin", "MONDO": "mondo", + "MONET": "Claude Monet Memeory Coin", "MONETA": "Moneta", "MONEY": "MoneyCoin", "MONEYBEE": "MONEYBEE", @@ -9130,6 +9204,7 @@ "MONKEY": "Monkey", "MONKEYS": "Monkeys Token", "MONKU": "Monku", + "MONKY": "Wise Monkey", "MONO": "MonoX", "MONOLITH": "Monolith", "MONONOKEINU": "Mononoke Inu", @@ -9144,7 +9219,10 @@ "MOOBIFI": "Staked BIFI", "MOOCAT": "MooCat", "MOODENG": "Moo Deng (moodengsol.com)", + "MOODENGBNB": "MOODENG (moodengbnb.com)", + "MOODENGSBS": "Moo Deng (moodeng.sbs)", "MOODENGSPACE": "MOO DENG", + "MOODENGVIP": "MOO DENG (moodeng.vip)", "MOODENGWIF": "MOODENGWIF", "MOOI": "Moonai", "MOOLA": "Degen Forest", @@ -9179,6 +9257,7 @@ "MORE": "More Coin", "MOREGEN": "MoreGen FreeMoon", "MORFEY": "Morfey", + "MORI": "MEMENTO•MORI (Runes)", "MOROS": "MOROS NET", "MORPH": "Morpheus Token", "MORPHO": "Morpho", @@ -9196,7 +9275,7 @@ "MOUTAI": "Moutai", "MOV": "MovieCoin", "MOVD": "MOVE Network", - "MOVE": "MarketMove", + "MOVE": "Movement", "MOVER": "Mover", "MOVEUSD": "MoveMoney USD", "MOVEY": "Movey", @@ -9345,6 +9424,7 @@ "MUN": "MUNcoin", "MUNCH": "Munch Token", "MUNCHY": "Boys Club Munchy", + "MUNDI": "Salvator Mundi", "MUNI": "Uniswap Protocol Token (Multichain)", "MUNITY": "Metahorse Unity", "MUNK": "Dramatic Chipmunk", @@ -9571,6 +9651,7 @@ "NEIROONB": "Neiro on Base", "NEKI": "Neki Token", "NEKO": "The Neko", + "NEKOARC": "Neko Arc", "NEKOIN": "Nekoin", "NEKOS": "Nekocoin", "NEMO": "NEMO", @@ -9730,6 +9811,7 @@ "NIPPY": "Cat On Catnip", "NIQAB": "NIQAB WORLD ORDER", "NIRV": "Nirvana NIRV", + "NIRVA": "Nirvana", "NIT": "Nesten", "NITEFEEDER": "Nitefeeder", "NITO": "Nitroken", @@ -9785,6 +9867,7 @@ "NOIZ": "NOIZ", "NOKA": "Noka Solana AI", "NOKU": "NOKU Master token", + "NOKUV1": "NOKU Master token v1", "NOLA": "Nola", "NOM": "Finom NOM Token", "NOMNOM": "nomnom", @@ -10008,7 +10091,7 @@ "OCTAX": "OctaX", "OCTI": "Oction", "OCTO": "OctoFi", - "OCTOC": "OctoCoin", + "OCTOCOIN": "Octocoin", "OCTOIN": "Octoin Coin", "OCW": "Online Cold Wallet", "OCX": "Original Crypto Coin", @@ -10189,6 +10272,7 @@ "OPS": "Octopus Protocol", "OPSC": "OpenSourceCoin", "OPSEC": "OpSec", + "OPSECV1": "OpSec v1", "OPSV1": "Octopus Protocol v1", "OPSV2": "Octopus Protocol v2", "OPT": "Opus", @@ -10202,6 +10286,7 @@ "OPTION": "OptionCoin", "OPU": "Opu Coin", "OPUL": "Opulous", + "OPUS": "Opus", "OPV": "OpenLive NFT", "OPXVEVELO": "OpenX Locked Velo", "ORA": "Oracolxor", @@ -10413,6 +10498,7 @@ "PARQ": "PARQ", "PARRY": "Parry Parrot", "PART": "Particl", + "PARTY": "Party", "PAS": "Passive Coin", "PASC": "Pascal Coin", "PASG": "Passage", @@ -10460,7 +10546,9 @@ "PBR": "PolkaBridge", "PBRV1": "PolkaBridge v1", "PBT": "Primalbase", + "PBTC": "pTokens BTC", "PBTC35A": "pBTC35A", + "PBTCV1": "pTokens BTC v1", "PBUX": "Playbux", "PBX": "Probinex", "PBXV1": "Probinex v1", @@ -10546,7 +10634,8 @@ "PENDY": "Pendy", "PENG": "Peng", "PENGCOIN": "PENG", - "PENGU": "Penguiana", + "PENGU": "Pudgy Penguins", + "PENGUI": "Penguiana", "PENGYX": "PengyX", "PENIS": "PenisGrow", "PENJ": "Penjamin Blinkerton", @@ -10622,6 +10711,7 @@ "PEPPA": "PEPPA", "PEPPER": "Pepper Token", "PEPS": "PEPS Coin", + "PEPU": "Pepe Unchained", "PEPURAI": "PEPURAI", "PEPVERS": "PepVerse", "PEPY": "Pepy", @@ -10681,7 +10771,6 @@ "PHAUNTEM": "Phauntem", "PHB": "Phoenix Global [v2]", "PHBD": "Polygon HBD", - "PHC": "Profit Hunters Coin", "PHCR": "PhotoChromic", "PHEN": "Phenx", "PHEX": "HEX (Polygon Portal)", @@ -10948,6 +11037,7 @@ "POLYX": "Polymesh", "POM": "Proof Of Memes", "PON": "Ponder", + "PONCH": "Ponchiqs", "PONCHO": "Poncho", "POND": "Marlin", "PONGO": "Pongo", @@ -11021,6 +11111,7 @@ "POWR": "Power Ledger", "POWSCHE": "Powsche", "POX": "Monkey Pox", + "POZO": "Pozo Coin", "PP": "ProducePay Chain", "PPAD": "PlayPad", "PPALPHA": "Phoenix Protocol", @@ -11087,6 +11178,7 @@ "PROB": "ProBit Token", "PROC": "ProCurrency", "PROD": "Productivist", + "PROFITHUNTERS": "Profit Hunters Coin", "PROGE": "Protector Roge", "PROJECT89": "Project89", "PROLIFIC": "Prolific Game Studio", @@ -11313,6 +11405,7 @@ "QLINDO": "QLINDO", "QLIX": "QLix", "QMALL": "QMALL TOKEN", + "QMV": "Qumva Network", "QNT": "Quant", "QNTR": "Quantor", "QNTU": "Quanta", @@ -11357,11 +11450,13 @@ "QUARK": "Quark", "QUARTZ": "Sandclock", "QUASA": "Quasacoin", + "QUASAR": "Quasar", "QUB": "Qubism", "QUBE": "Qube", "QUBIC": "Qubic", "QUBITICA": "Qubitica", "QUBY": "Quby", + "QUDEFI": "Qudefi", "QUE": "Queen Of Memes", "QUEEN": "Queen of Engrand", "QUICK": "Quickswap", @@ -11467,6 +11562,7 @@ "RBLZ": "RebelSatoshi", "RBN": "Ribbon Finance", "RBNB": "StaFi Staked BNB", + "RBNT": "Redbelly Network", "RBP": "Rare Ball Potion", "RBR": "Ribbit Rewards", "RBRETT": "ROARING BRETT", @@ -11483,6 +11579,7 @@ "RCC": "Reality Clash", "RCCC": "RCCC", "RCG": "Recharge", + "RCGE": "RCGE", "RCH": "Rich", "RCKT": "RocketSwap", "RCM": "READ2N", @@ -11707,6 +11804,7 @@ "RIZO": "HahaYes", "RIZOLOL": "Rizo", "RIZZ": "Rizz", + "RIZZMAS": "Rizzmas", "RJV": "Rejuve.AI", "RKC": "Royal Kingdom Coin", "RKI": "RAKHI", @@ -11717,6 +11815,7 @@ "RLC": "iExec", "RLM": "MarbleVerse", "RLOOP": "rLoop", + "RLP": "Resolv RLP", "RLT": "Runner Land", "RLUSD": "Ripple USD", "RLX": "Relex", @@ -11779,6 +11878,7 @@ "RONCOIN": "RON", "ROND": "ROND", "RONIN": "Ronin", + "RONNIE": "Ronnie", "ROO": "Lucky Roo", "ROOBEE": "ROOBEE", "ROOK": "KeeperDAO", @@ -11789,6 +11889,7 @@ "ROOT": "The Root Network", "ROOTCOIN": "RootCoin", "ROOTS": "RootProject", + "ROPIRITO": "Ropirito", "ROS": "ROS Coin", "ROSA": "Rosa Inu", "ROSE": "Oasis Labs", @@ -11854,6 +11955,7 @@ "RSWETH": "Restaked Swell Ethereum", "RT2": "RotoCoin", "RTB": "AB-CHAIN", + "RTBL": "Rolling T-bill", "RTC": "Reltime", "RTD": "Retard", "RTE": "Rate3", @@ -11885,6 +11987,7 @@ "RUNY": "Runy", "RUP": "Rupee", "RUPX": "Rupaya", + "RURI": "Ruri - Truth Terminal's Crush", "RUSD": "Reflecto USD", "RUSH": "RUSH COIN", "RUSHCMC": "RUSHCMC", @@ -11899,6 +12002,7 @@ "RVL": "Revolotto", "RVLNG": "RevolutionGames", "RVLT": "Revolt 2 Earn", + "RVLTV1": "Revolt 2 Earn v1", "RVM": "Realvirm", "RVN": "Ravencoin", "RVO": "AhrvoDEEX", @@ -12006,6 +12110,7 @@ "SANSHU": "Sanshu Inu", "SANTA": "SANTA CHRISTMAS INU", "SANTAGROK": "Santa Grok", + "SANTAHAT": "SANTA HAT", "SANTOS": "Santos FC Fan Token", "SAO": "Sator", "SAP": "SwapAll", @@ -12370,6 +12475,7 @@ "SHINT": "Shiba Interstellar", "SHIP": "ShipChain", "SHIR": "SHIRO", + "SHIRO": "Shiro Neko", "SHIRYOINU": "Shiryo-Inu", "SHISHA": "Shisha Coin", "SHIT": "I will poop it NFT", @@ -12494,10 +12600,12 @@ "SKET": "Sketch coin", "SKEY": "SmartKey", "SKG888": "Safu & Kek Gigafundz 888", - "SKI": "Skillchain", + "SKI": "Ski Mask Dog", "SKIBIDI": "Skibidi Toilet", + "SKICAT": "SKI MASK CAT", "SKID": "Success Kid", "SKILL": "CryptoBlades", + "SKILLC": "Skillchain", "SKIN": "Skincoin", "SKING": "Solo King", "SKINS": "Coins & Skins", @@ -12797,6 +12905,7 @@ "SOONCOIN": "SoonCoin", "SOOTCASE": "I like my sootcase", "SOP": "SoPay", + "SOPH": "Sophon", "SOPHON": "Sophon (Atomicals)", "SOR": "Sorcery", "SORA": "Sora Validator Token", @@ -12806,6 +12915,7 @@ "SORAI": "Sora AI", "SORAPORN": "Sora Porn", "SOSNOVKINO": "Sosnovkino", + "SOSWAP": "Solana Swap", "SOT": "Soccer Crypto", "SOTA": "SOTA Finance", "SOUL": "Phantasma", @@ -12817,6 +12927,7 @@ "SOV": "Sovryn", "SOVE": "Soverain", "SOVI": "Sovi Finance", + "SOVRN": "Sovrun", "SOWA": "Sowa AI", "SOX": "Nobby Game", "SOY": "Soy Finance", @@ -12971,6 +13082,7 @@ "SSB": "SatoshiStreetBets", "SSC": "SelfSell", "SSD": "Sonic Screw Driver Coin", + "SSDX": "SpunkySDX", "SSE": "Soroosh Smart Ecosystem", "SSG": "Surviving Soldiers", "SSGT": "Safeswap", @@ -12997,7 +13109,7 @@ "STABLZ": "Stablz", "STAC": "STAC", "STACK": "StackOS", - "STACKS": "STACKS", + "STACKS": " STACKS PAY", "STACS": "STACS Token", "STAK": "Jigstack", "STAKE": "xDai Chain", @@ -13011,6 +13123,7 @@ "STARAMBA": "Staramba", "STARBASE": "Starbase", "STARC": "StarChain", + "STARDOGE": "StarDOGE", "STARL": "StarLink", "STARLAUNCH": "StarLaunch", "STARLY": "Starly", @@ -13035,18 +13148,22 @@ "STATOKEN": "STA", "STATOM": "Stride Staked ATOM", "STATS": "Stats", + "STAU": "STAU", "STAX": "Staxcoin", "STAY": "NFsTay", "STBOT": "SolTradingBot", + "STBTC": "Lorenzo stBTC", "STBU": "Stobox Token", "STC": "Satoshi Island", "STCN": "Stakecoin", "STD": "STEED", "STDYDX": "Stride Staked DYDX", "STEAK": "SteakHut Finance", + "STEAKUSDC": "Steakhouse USDC Morpho Vault", "STEALTH": "StealthPad", "STEAMPUNK": "SteamPunk", "STEAMX": "Steam Exchange", + "STEEL": "SteelCoin", "STEEM": "Steem", "STEEMD": "Steem Dollars", "STEEP": "SteepCoin", @@ -13092,6 +13209,7 @@ "STMX": "StormX", "STND": "Standard Protocol", "STNEAR": "Staked NEAR", + "STNK": "Stonks", "STO": "Save The Ocean", "STOC": "STO Cash", "STOG": "Stooges", @@ -13176,6 +13294,7 @@ "SUGAR": "Sugar Exchange", "SUI": "Sui", "SUIA": "SUIA", + "SUIAI": "SUI Agents", "SUIB": "Suiba Inu", "SUIJAK": "Suijak", "SUILAMA": "Suilama", @@ -13226,6 +13345,8 @@ "SUPERT": "Super Trump", "SUPERTX": "SuperTX", "SUPR": "SuperDapp", + "SUPRA": "Supra", + "SUPREMEFINANCE": "Hype", "SUR": "Suretly", "SURE": "inSure", "SURF": "Surf.Finance", @@ -13233,6 +13354,7 @@ "SUSD": "sUSD", "SUSDA": "sUSDa", "SUSDE": "Ethena Staked USDe", + "SUSDS": "Savings USDS", "SUSDX": "Staked USDX", "SUSHI": "Sushi", "SUSX": "Savings USX", @@ -13333,6 +13455,8 @@ "SYNCG": "SyncGPT", "SYNCN": "Sync Network", "SYNCO": "Synco", + "SYNDOG": "Synthesizer Dog", + "SYNK": "Synk", "SYNLEV": "SynLev", "SYNO": "Synonym Finance", "SYNR": "MOBLAND", @@ -13395,6 +13519,7 @@ "TARA": "Taraxa", "TARAL": "TARALITY", "TARD": "Tard", + "TARDI": "Tardi", "TARI": "Tari World", "TAROT": "Tarot", "TAROTV1": "Tarot v1", @@ -13414,6 +13539,7 @@ "TAVA": "ALTAVA", "TAX": "MetaToll", "TAXI": "Robotaxi", + "TAXLESSTRUMP": "MAGA TAXLESS", "TBAC": "BlockAura", "TBANK": "TaoBank", "TBAR": "Titanium BAR", @@ -13457,6 +13583,7 @@ "TCY": "The Crypto You", "TD": "The Big Red", "TDAN": "TDAN", + "TDC": "Tidecoin", "TDE": "Trade Ecology Token", "TDEFI": "Token Teknoloji A.S. Token DeFi", "TDFB": "TDFB", @@ -13523,10 +13650,11 @@ "TEST": "Test", "TESTA": "Testa", "TET": "Tectum", - "TETHER": "Hermione", + "TETH": "Treehouse ETH", "TETHYS": "Tethys", "TETRA": "Tetra", "TETU": "TETU", + "TEVA": "Tevaera", "TEW": "Trump in a memes world", "TF47": "Trump Force 47", "TFBX": "Truefeedback Token", @@ -13591,6 +13719,7 @@ "THR": "Thorecoin", "THREE": "Three Protocol Token ", "THRT": "ThriveToken", + "THRUST": "Thruster", "THRY": "THEORY", "THS": "TechShares", "THT": "Thought", @@ -13669,6 +13798,7 @@ "TLP": "TulipCoin", "TLW": "TILWIKI", "TMAGA": "THE MAGA MOVEMENT", + "TMAI": "Token Metrics AI", "TMANIA": "Trump Mania", "TME": "Timereum", "TMED": "MDsquare", @@ -13721,6 +13851,7 @@ "TOMB": "Tomb", "TOMC": "TOM CAT", "TOMI": "tomiNet", + "TOMO": "Tomo Cat", "TOMOE": "TomoChain ERC20", "TOMS": "TomTomCoin", "TON": "Toncoin", @@ -13800,6 +13931,7 @@ "TRAC": "OriginTrail", "TRACE": "Trace Network Labs", "TRACEA": "Trace AI", + "TRACKEDBIO": "TrackedBio", "TRACN": "trac (Ordinals)", "TRADE": "Polytrade", "TRADEBOT": "TradeBot", @@ -13830,7 +13962,7 @@ "TRDT": "Trident", "TREAT": "Treat", "TRECENTO": "Trecento Blockchain Capital", - "TREE": "HyperionX", + "TREE": "Tree", "TREEB": "Retreeb", "TREMP": "Doland Tremp", "TRESTLE": "TRESTLE", @@ -14330,6 +14462,7 @@ "UTKV1": "Utrust", "UTMDOGE": "UltramanDoge", "UTNP": "Universa", + "UTON": "uTON", "UTT": "United Traders Token", "UTU": "UTU Protocol", "UTX": "UTIX", @@ -14363,7 +14496,7 @@ "VALUE": "Value Liquidity", "VAMPIRE": "Vampire Inu", "VAN": "Vanspor Token", - "VANA": "Nirvana", + "VANA": "Vana", "VANCAT": "Vancat", "VANCE": "JD Vance", "VANF": "Van Fwogh", @@ -14523,6 +14656,8 @@ "VITAFAST": "Molecules of Korolchuk IP-NFT", "VITAL": "Vital Network", "VITALI": "Vitalik's Casper", + "VITAMINS": "Vitamins", + "VITARNA": "VitaRNA", "VITE": "VITE", "VITRA": "Vitra Studios", "VITY": "Vitteey", @@ -14547,6 +14682,7 @@ "VLUNA": "Venus Luna", "VLX": "Velas", "VLXPAD": "VelasPad", + "VMANTA": "Bifrost Voucher MANTA", "VMATIC": "Venus MATIC", "VMC": "VirtualMining Coin", "VME": "TrueVett", @@ -14632,6 +14768,7 @@ "VSOL": "VSolidus", "VSP": "Vesper Finance", "VSTA": "Vesta Finance", + "VSTR": "Vestra DAO", "VSUI": "Volo Staked SUI", "VSX": "Vsync", "VSYS": "V Systems", @@ -14668,6 +14805,7 @@ "VXRP": "Venus XRP", "VXT": "Voxto Amplify", "VXV": "Vectorspace AI", + "VY": "Valinity", "VYBE": "Vybe", "VYFI": "VyFinance", "VYNC": "VYNK Chain", @@ -14730,6 +14868,7 @@ "WARPED": "Warped Games", "WARPIE": "Warpie", "WARS": "MetaWars", + "WART": "Warthog", "WAS": "Wasder", "WASABI": "WasabiX", "WASD": "WASD Studios", @@ -14750,6 +14889,7 @@ "WAXS": "Axie Infinity Shards (Wormhole)", "WAY": "WayCoin", "WAZ": "MikeAI", + "WBAN": "Wrapped Banano", "WBB": "Wild Beast Coin", "WBBC": "Wibcoin", "WBC": "WorldBrain Coin", @@ -14828,6 +14968,7 @@ "WELL": "Moonwell", "WELLTOKEN": "Well", "WELLV1": "Moonwell v1", + "WELON": "WrappedElon", "WELSH": "Welshcorgicoin", "WELT": "Fabwelt", "WELUPS": "Welups Blockchain", @@ -14839,6 +14980,7 @@ "WENLAMBO": "Wenlambo", "WEOS": "Wrapped EOS", "WEPC": "World Earn & Play Community", + "WERK": "Werk Family", "WEST": "Waves Enterprise", "WET": "WeShow Token", "WETH": "WETH", @@ -14985,7 +15127,8 @@ "WMN": "WebMind Network", "WMNT": "Wrapped Mantle", "WMOXY": "Moxy", - "WMT": "World Mobile Token", + "WMT": "World Mobile Token v1", + "WMTX": "World Mobile Token", "WMW": "WoopMoney", "WMX": "Wombex Finance", "WMXWOM": "Wombex WOM", @@ -15139,6 +15282,7 @@ "WXRP": "Wrapped XRP", "WXT": "WXT", "WXTZ": "Wrapped Tezos", + "WYAC": "Woman Yelling At Cat", "WYN": "Wynn", "WYNN": "Anita Max Wynn", "WYS": "Wysker", @@ -15168,6 +15312,7 @@ "XALGO": "Wrapped ALGO", "XALPHA": "XAlpha AI", "XAMP": "Antiample", + "XAND": "Xandeum", "XANK": "Xank", "XAP": "Apollon", "XAR": "Arcana Network", @@ -15305,6 +15450,7 @@ "XING": "Xing Xing", "XINU": "XINU", "XIO": "Blockzero Labs", + "XION": "XION", "XIOS": "Xios", "XIOT": "Xiotri", "XIV": "Project Inverse", @@ -15334,6 +15480,7 @@ "XMN": "Motion", "XMO": "Monero Original", "XMON": "XMON", + "XMOON": "r/CryptoCurrency Moons v1", "XMP": "Mapt.Coin", "XMR": "Monero", "XMRG": "Monero Gold", @@ -15418,7 +15565,6 @@ "XRP": "XRP", "XRP2": "XRP2.0", "XRP20": "XRP20", - "XRP8": "HarryPotterObamaPacMan8Inu", "XRPAYNET": "XRPayNet", "XRPC": "Xrp Classic", "XRPCHAIN": "Ripple Chain", @@ -15525,6 +15671,7 @@ "YAYCOIN": "YAYcoin", "YBC": "YbCoin", "YBO": "Young Boys Fan Token", + "YBR": "YieldBricks", "YCC": "Yuan Chain Coin", "YCE": "MYCE", "YCO": "Y Coin", @@ -15538,6 +15685,7 @@ "YEE": "Yeeco", "YEED": "Yggdrash", "YEEHAW": "YEEHAW", + "YEETI": "YEETI 液体", "YEFI": "YeFi", "YEL": "Yel.Finance", "YEON": "Yeon", @@ -15603,6 +15751,7 @@ "YOUNES": "YOUNES", "YOURAI": "YOUR AI", "YOURMOM": "YOUR MOM DOG", + "YOUSIM": "YouSim", "YOVI": "YobitVirtualCoin", "YOYOW": "Yoyow", "YPC": "YoungParrot", @@ -15625,6 +15774,7 @@ "YUKI": "YUKI", "YUKIE": "Yukie", "YUKKY": "YUKKY", + "YUKO": "YUKO", "YUM": "Yumerium", "YUMMI": "Yummi Universe", "YUMMY": "Yummy", @@ -15689,8 +15839,7 @@ "ZEBU": "ZEBU", "ZEC": "ZCash", "ZECD": "ZCashDarkCoin", - "ZED": "ZED Token", - "ZEDCOIN": "ZedCoin", + "ZED": "ZedCoins", "ZEDD": "ZedDex", "ZEDTOKEN": "Zed Token", "ZEDX": "ZEDXION", @@ -15729,9 +15878,11 @@ "ZEUM": "Colizeum", "ZEUS": "Zeus Network", "ZEUSPEPES": "Zeus", + "ZEX": "Zeta", "ZEXI": "ZEXICON", "ZEXY": "ZEXY", "ZF": "zkSwap Finance ", + "ZFI": "Zyfi", "ZFL": "Zuflo Coin", "ZFLOKI": "zkFloki", "ZFM": "ZFMCOIN", @@ -15791,7 +15942,8 @@ "ZKX": "ZKX", "ZKZ": "Zkzone", "ZLA": "Zilla", - "ZLDA": "Zelda Inu", + "ZLDA": "ZELDA 2.0", + "ZLDAV1": "ZELDA v1", "ZLK": "Zenlink Network", "ZLOT": "zLOT Finance", "ZLP": "ZilPay Wallet", @@ -15812,6 +15964,7 @@ "ZODI": "Zodium", "ZOE": "Zoe Cash", "ZOI": "Zoin", + "ZON": "Zon Token", "ZONE": "Zone", "ZONO": "Zono Swap", "ZONX": "METAZONX", From bbbd974be64f4f88d494c3e9ab9eecce8f35358e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 2 Jan 2025 06:35:11 +0100 Subject: [PATCH 6/8] Bugfix/improve handling of missing url in logo service (#4171) * Improve handling of missing url * Update changelog --- CHANGELOG.md | 4 ++++ apps/api/src/app/logo/logo.service.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aa7a13b4..b2b66f56c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the language localization for German (`de`) - Refreshed the cryptocurrencies list +### Fixed + +- Improved the handling of a missing url in the endpoint to fetch the logo of an asset or a platform + ## 2.132.0 - 2024-12-30 ### Added diff --git a/apps/api/src/app/logo/logo.service.ts b/apps/api/src/app/logo/logo.service.ts index 584f50cab..d245faa29 100644 --- a/apps/api/src/app/logo/logo.service.ts +++ b/apps/api/src/app/logo/logo.service.ts @@ -28,7 +28,7 @@ export class LogoService { { dataSource, symbol } ]); - if (!assetProfile) { + if (!assetProfile?.url) { throw new HttpException( getReasonPhrase(StatusCodes.NOT_FOUND), StatusCodes.NOT_FOUND From 87f6357d74418adf252d492bc166a99a6accc46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20=C5=81=C4=85giewka?= Date: Thu, 2 Jan 2025 10:09:40 +0100 Subject: [PATCH 7/8] Feature/send original MIME type in logo endpoint (#4173) * Send original MIME type in logo endpoint * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/logo/logo.controller.ts | 15 ++++++++------- apps/api/src/app/logo/logo.service.ts | 17 +++++++++++------ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2b66f56c..a973acf3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the endpoint to fetch the logo of an asset or a platform by sending the original MIME type - Eliminated `got` in favor of using `fetch` - Changed the `REDIS_HOST` from `localhost` to `redis` in `.env.example` - Changed the _Postgres_ host from `localhost` to `postgres` in `.env.example` diff --git a/apps/api/src/app/logo/logo.controller.ts b/apps/api/src/app/logo/logo.controller.ts index 0982a793f..fdbe430c9 100644 --- a/apps/api/src/app/logo/logo.controller.ts +++ b/apps/api/src/app/logo/logo.controller.ts @@ -26,12 +26,13 @@ export class LogoController { @Res() response: Response ) { try { - const buffer = await this.logoService.getLogoByDataSourceAndSymbol({ - dataSource, - symbol - }); + const { buffer, type } = + await this.logoService.getLogoByDataSourceAndSymbol({ + dataSource, + symbol + }); - response.contentType('image/png'); + response.contentType(type); response.send(buffer); } catch { response.status(HttpStatus.NOT_FOUND).send(); @@ -44,9 +45,9 @@ export class LogoController { @Res() response: Response ) { try { - const buffer = await this.logoService.getLogoByUrl(url); + const { buffer, type } = await this.logoService.getLogoByUrl(url); - response.contentType('image/png'); + response.contentType(type); response.send(buffer); } catch { response.status(HttpStatus.NOT_FOUND).send(); diff --git a/apps/api/src/app/logo/logo.service.ts b/apps/api/src/app/logo/logo.service.ts index d245faa29..ba1acdd29 100644 --- a/apps/api/src/app/logo/logo.service.ts +++ b/apps/api/src/app/logo/logo.service.ts @@ -38,12 +38,12 @@ export class LogoService { return this.getBuffer(assetProfile.url); } - public async getLogoByUrl(aUrl: string) { + public getLogoByUrl(aUrl: string) { return this.getBuffer(aUrl); } - private getBuffer(aUrl: string) { - return fetch( + private async getBuffer(aUrl: string) { + const blob = await fetch( `https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${aUrl}&size=64`, { headers: { 'User-Agent': 'request' }, @@ -51,8 +51,13 @@ export class LogoService { this.configurationService.get('REQUEST_TIMEOUT') ) } - ) - .then((res) => res.arrayBuffer()) - .then((buffer) => Buffer.from(buffer)); + ).then((res) => res.blob()); + + return { + buffer: await blob.arrayBuffer().then((arrayBuffer) => { + return Buffer.from(arrayBuffer); + }), + type: blob.type + }; } } From 02681cc4791aa4c08198b0c95d01d88471d357aa Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 2 Jan 2025 10:21:58 +0100 Subject: [PATCH 8/8] Feature/add snack bar to copy link to clipboard action in access table (#4175) * Add snack bar * Update changelog --- CHANGELOG.md | 1 + .../access-table/access-table.component.html | 2 +- .../access-table/access-table.component.ts | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a973acf3e..c712f1ffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the usability of the _Copy link to clipboard_ action by adding a confirmation on success in the access table to share the portfolio - Improved the endpoint to fetch the logo of an asset or a platform by sending the original MIME type - Eliminated `got` in favor of using `fetch` - Changed the `REDIS_HOST` from `localhost` to `redis` in `.env.example` diff --git a/apps/client/src/app/components/access-table/access-table.component.html b/apps/client/src/app/components/access-table/access-table.component.html index 2a20e4631..44aee1644 100644 --- a/apps/client/src/app/components/access-table/access-table.component.html +++ b/apps/client/src/app/components/access-table/access-table.component.html @@ -66,7 +66,7 @@ @if (element.type === 'PUBLIC') { -
diff --git a/apps/client/src/app/components/access-table/access-table.component.ts b/apps/client/src/app/components/access-table/access-table.component.ts index da8ceb094..32ae7bfef 100644 --- a/apps/client/src/app/components/access-table/access-table.component.ts +++ b/apps/client/src/app/components/access-table/access-table.component.ts @@ -12,6 +12,7 @@ import { OnChanges, Output } from '@angular/core'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { MatTableDataSource } from '@angular/material/table'; @Component({ @@ -34,7 +35,8 @@ export class AccessTableComponent implements OnChanges { public constructor( private clipboard: Clipboard, - private notificationService: NotificationService + private notificationService: NotificationService, + private snackBar: MatSnackBar ) {} public ngOnChanges() { @@ -55,8 +57,16 @@ export class AccessTableComponent implements OnChanges { return `${this.baseUrl}/${languageCode}/p/${aId}`; } - public onCopyToClipboard(aId: string): void { + public onCopyUrlToClipboard(aId: string): void { this.clipboard.copy(this.getPublicUrl(aId)); + + this.snackBar.open( + '✅ ' + $localize`Link has been copied to the clipboard`, + undefined, + { + duration: 3000 + } + ); } public onDeleteAccess(aId: string) {