@merkl/api 0.20.41 → 0.20.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/eden/index.d.ts +15 -63
- package/dist/src/index.d.ts +3 -15
- package/dist/src/modules/v4/coingecko/coingecko.model.d.ts +0 -0
- package/dist/src/modules/v4/coingecko/coingecko.model.js +1 -0
- package/dist/src/modules/v4/coingecko/coingecko.repository.d.ts +14 -0
- package/dist/src/modules/v4/coingecko/coingecko.repository.js +9 -0
- package/dist/src/modules/v4/coingecko/coingecko.service.d.ts +16 -0
- package/dist/src/modules/v4/coingecko/coingecko.service.js +65 -0
- package/dist/src/modules/v4/router.d.ts +3 -15
- package/dist/src/modules/v4/token/token.controller.d.ts +3 -15
- package/dist/src/modules/v4/token/token.controller.js +0 -5
- package/dist/src/modules/v4/token/token.model.d.ts +1 -0
- package/dist/src/modules/v4/token/token.model.js +1 -0
- package/dist/src/modules/v4/token/token.repository.js +1 -0
- package/dist/src/modules/v4/token/token.service.d.ts +1 -2
- package/dist/src/modules/v4/token/token.service.js +21 -37
- package/dist/src/scripts/fill-coingecko-data.d.ts +1 -0
- package/dist/src/scripts/fill-coingecko-data.js +3 -0
- package/dist/tsconfig.package.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/src/eden/index.d.ts
CHANGED
@@ -1837,6 +1837,7 @@ declare const eden: {
|
|
1837
1837
|
isNative?: boolean | undefined;
|
1838
1838
|
test?: boolean | undefined;
|
1839
1839
|
missingIcons?: boolean | undefined;
|
1840
|
+
missingPrice?: boolean | undefined;
|
1840
1841
|
};
|
1841
1842
|
fetch?: RequestInit | undefined;
|
1842
1843
|
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
@@ -1883,7 +1884,7 @@ declare const eden: {
|
|
1883
1884
|
isPoint: boolean;
|
1884
1885
|
isNative: boolean;
|
1885
1886
|
price: number | null;
|
1886
|
-
}
|
1887
|
+
};
|
1887
1888
|
}>>;
|
1888
1889
|
};
|
1889
1890
|
count: {
|
@@ -1900,23 +1901,13 @@ declare const eden: {
|
|
1900
1901
|
isNative?: boolean | undefined;
|
1901
1902
|
test?: boolean | undefined;
|
1902
1903
|
missingIcons?: boolean | undefined;
|
1904
|
+
missingPrice?: boolean | undefined;
|
1903
1905
|
};
|
1904
1906
|
fetch?: RequestInit | undefined;
|
1905
1907
|
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
1906
1908
|
200: number;
|
1907
1909
|
}>>;
|
1908
1910
|
};
|
1909
|
-
icons: {
|
1910
|
-
post: (body: unknown, options: {
|
1911
|
-
headers: {
|
1912
|
-
authorization: string;
|
1913
|
-
};
|
1914
|
-
query?: Record<string, unknown> | undefined;
|
1915
|
-
fetch?: RequestInit | undefined;
|
1916
|
-
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
1917
|
-
200: void;
|
1918
|
-
}>>;
|
1919
|
-
};
|
1920
1911
|
webhooks: {
|
1921
1912
|
notion: {
|
1922
1913
|
post: (body: {
|
@@ -5656,6 +5647,7 @@ declare const eden: {
|
|
5656
5647
|
isNative?: boolean | undefined;
|
5657
5648
|
test?: boolean | undefined;
|
5658
5649
|
missingIcons?: boolean | undefined;
|
5650
|
+
missingPrice?: boolean | undefined;
|
5659
5651
|
};
|
5660
5652
|
fetch?: RequestInit | undefined;
|
5661
5653
|
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
@@ -5702,7 +5694,7 @@ declare const eden: {
|
|
5702
5694
|
isPoint: boolean;
|
5703
5695
|
isNative: boolean;
|
5704
5696
|
price: number | null;
|
5705
|
-
}
|
5697
|
+
};
|
5706
5698
|
}>>;
|
5707
5699
|
};
|
5708
5700
|
count: {
|
@@ -5719,23 +5711,13 @@ declare const eden: {
|
|
5719
5711
|
isNative?: boolean | undefined;
|
5720
5712
|
test?: boolean | undefined;
|
5721
5713
|
missingIcons?: boolean | undefined;
|
5714
|
+
missingPrice?: boolean | undefined;
|
5722
5715
|
};
|
5723
5716
|
fetch?: RequestInit | undefined;
|
5724
5717
|
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
5725
5718
|
200: number;
|
5726
5719
|
}>>;
|
5727
5720
|
};
|
5728
|
-
icons: {
|
5729
|
-
post: (body: unknown, options: {
|
5730
|
-
headers: {
|
5731
|
-
authorization: string;
|
5732
|
-
};
|
5733
|
-
query?: Record<string, unknown> | undefined;
|
5734
|
-
fetch?: RequestInit | undefined;
|
5735
|
-
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
5736
|
-
200: void;
|
5737
|
-
}>>;
|
5738
|
-
};
|
5739
5721
|
webhooks: {
|
5740
5722
|
notion: {
|
5741
5723
|
post: (body: {
|
@@ -10544,6 +10526,7 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
10544
10526
|
isNative?: boolean | undefined;
|
10545
10527
|
test?: boolean | undefined;
|
10546
10528
|
missingIcons?: boolean | undefined;
|
10529
|
+
missingPrice?: boolean | undefined;
|
10547
10530
|
};
|
10548
10531
|
headers: unknown;
|
10549
10532
|
response: {
|
@@ -10581,6 +10564,7 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
10581
10564
|
isNative?: boolean | undefined;
|
10582
10565
|
test?: boolean | undefined;
|
10583
10566
|
missingIcons?: boolean | undefined;
|
10567
|
+
missingPrice?: boolean | undefined;
|
10584
10568
|
};
|
10585
10569
|
headers: unknown;
|
10586
10570
|
response: {
|
@@ -10618,7 +10602,7 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
10618
10602
|
isPoint: boolean;
|
10619
10603
|
isNative: boolean;
|
10620
10604
|
price: number | null;
|
10621
|
-
}
|
10605
|
+
};
|
10622
10606
|
};
|
10623
10607
|
};
|
10624
10608
|
};
|
@@ -10659,20 +10643,6 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
10659
10643
|
};
|
10660
10644
|
};
|
10661
10645
|
};
|
10662
|
-
} & {
|
10663
|
-
icons: {
|
10664
|
-
post: {
|
10665
|
-
body: unknown;
|
10666
|
-
params: {};
|
10667
|
-
query: unknown;
|
10668
|
-
headers: {
|
10669
|
-
authorization: string;
|
10670
|
-
};
|
10671
|
-
response: {
|
10672
|
-
200: void;
|
10673
|
-
};
|
10674
|
-
};
|
10675
|
-
};
|
10676
10646
|
} & {
|
10677
10647
|
webhooks: {
|
10678
10648
|
notion: {
|
@@ -15881,6 +15851,7 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
15881
15851
|
isNative?: boolean | undefined;
|
15882
15852
|
test?: boolean | undefined;
|
15883
15853
|
missingIcons?: boolean | undefined;
|
15854
|
+
missingPrice?: boolean | undefined;
|
15884
15855
|
};
|
15885
15856
|
fetch?: RequestInit | undefined;
|
15886
15857
|
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
@@ -15927,7 +15898,7 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
15927
15898
|
isPoint: boolean;
|
15928
15899
|
isNative: boolean;
|
15929
15900
|
price: number | null;
|
15930
|
-
}
|
15901
|
+
};
|
15931
15902
|
}>>;
|
15932
15903
|
};
|
15933
15904
|
count: {
|
@@ -15944,23 +15915,13 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
15944
15915
|
isNative?: boolean | undefined;
|
15945
15916
|
test?: boolean | undefined;
|
15946
15917
|
missingIcons?: boolean | undefined;
|
15918
|
+
missingPrice?: boolean | undefined;
|
15947
15919
|
};
|
15948
15920
|
fetch?: RequestInit | undefined;
|
15949
15921
|
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
15950
15922
|
200: number;
|
15951
15923
|
}>>;
|
15952
15924
|
};
|
15953
|
-
icons: {
|
15954
|
-
post: (body: unknown, options: {
|
15955
|
-
headers: {
|
15956
|
-
authorization: string;
|
15957
|
-
};
|
15958
|
-
query?: Record<string, unknown> | undefined;
|
15959
|
-
fetch?: RequestInit | undefined;
|
15960
|
-
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
15961
|
-
200: void;
|
15962
|
-
}>>;
|
15963
|
-
};
|
15964
15925
|
webhooks: {
|
15965
15926
|
notion: {
|
15966
15927
|
post: (body: {
|
@@ -19700,6 +19661,7 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
19700
19661
|
isNative?: boolean | undefined;
|
19701
19662
|
test?: boolean | undefined;
|
19702
19663
|
missingIcons?: boolean | undefined;
|
19664
|
+
missingPrice?: boolean | undefined;
|
19703
19665
|
};
|
19704
19666
|
fetch?: RequestInit | undefined;
|
19705
19667
|
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
@@ -19746,7 +19708,7 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
19746
19708
|
isPoint: boolean;
|
19747
19709
|
isNative: boolean;
|
19748
19710
|
price: number | null;
|
19749
|
-
}
|
19711
|
+
};
|
19750
19712
|
}>>;
|
19751
19713
|
};
|
19752
19714
|
count: {
|
@@ -19763,23 +19725,13 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
19763
19725
|
isNative?: boolean | undefined;
|
19764
19726
|
test?: boolean | undefined;
|
19765
19727
|
missingIcons?: boolean | undefined;
|
19728
|
+
missingPrice?: boolean | undefined;
|
19766
19729
|
};
|
19767
19730
|
fetch?: RequestInit | undefined;
|
19768
19731
|
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
19769
19732
|
200: number;
|
19770
19733
|
}>>;
|
19771
19734
|
};
|
19772
|
-
icons: {
|
19773
|
-
post: (body: unknown, options: {
|
19774
|
-
headers: {
|
19775
|
-
authorization: string;
|
19776
|
-
};
|
19777
|
-
query?: Record<string, unknown> | undefined;
|
19778
|
-
fetch?: RequestInit | undefined;
|
19779
|
-
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
19780
|
-
200: void;
|
19781
|
-
}>>;
|
19782
|
-
};
|
19783
19735
|
webhooks: {
|
19784
19736
|
notion: {
|
19785
19737
|
post: (body: {
|
package/dist/src/index.d.ts
CHANGED
@@ -2195,6 +2195,7 @@ declare const app: Elysia<"", false, {
|
|
2195
2195
|
isNative?: boolean | undefined;
|
2196
2196
|
test?: boolean | undefined;
|
2197
2197
|
missingIcons?: boolean | undefined;
|
2198
|
+
missingPrice?: boolean | undefined;
|
2198
2199
|
};
|
2199
2200
|
headers: unknown;
|
2200
2201
|
response: {
|
@@ -2232,6 +2233,7 @@ declare const app: Elysia<"", false, {
|
|
2232
2233
|
isNative?: boolean | undefined;
|
2233
2234
|
test?: boolean | undefined;
|
2234
2235
|
missingIcons?: boolean | undefined;
|
2236
|
+
missingPrice?: boolean | undefined;
|
2235
2237
|
};
|
2236
2238
|
headers: unknown;
|
2237
2239
|
response: {
|
@@ -2269,7 +2271,7 @@ declare const app: Elysia<"", false, {
|
|
2269
2271
|
isPoint: boolean;
|
2270
2272
|
isNative: boolean;
|
2271
2273
|
price: number | null;
|
2272
|
-
}
|
2274
|
+
};
|
2273
2275
|
};
|
2274
2276
|
};
|
2275
2277
|
};
|
@@ -2310,20 +2312,6 @@ declare const app: Elysia<"", false, {
|
|
2310
2312
|
};
|
2311
2313
|
};
|
2312
2314
|
};
|
2313
|
-
} & {
|
2314
|
-
icons: {
|
2315
|
-
post: {
|
2316
|
-
body: unknown;
|
2317
|
-
params: {};
|
2318
|
-
query: unknown;
|
2319
|
-
headers: {
|
2320
|
-
authorization: string;
|
2321
|
-
};
|
2322
|
-
response: {
|
2323
|
-
200: void;
|
2324
|
-
};
|
2325
|
-
};
|
2326
|
-
};
|
2327
2315
|
} & {
|
2328
2316
|
webhooks: {
|
2329
2317
|
notion: {
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
"use strict";
|
@@ -0,0 +1,14 @@
|
|
1
|
+
export declare class CoingeckoRepository {
|
2
|
+
static findList(): Promise<{
|
3
|
+
id: string;
|
4
|
+
symbol: string;
|
5
|
+
name: string;
|
6
|
+
}[]>;
|
7
|
+
static findMarkets(ids?: string[]): Promise<{
|
8
|
+
id: string;
|
9
|
+
symbol: string;
|
10
|
+
name: string;
|
11
|
+
image: string;
|
12
|
+
current_price: number;
|
13
|
+
}[]>;
|
14
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import axios from "axios";
|
2
|
+
export class CoingeckoRepository {
|
3
|
+
static async findList() {
|
4
|
+
return (await axios.get("https://api.coingecko.com/api/v3/coins/list")).data;
|
5
|
+
}
|
6
|
+
static async findMarkets(ids) {
|
7
|
+
return (await axios.get(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&per_page=250${!!ids ? `&ids=${ids.join(",")}` : ""}`)).data;
|
8
|
+
}
|
9
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
export declare class CoingeckoService {
|
2
|
+
static findList(): Promise<{
|
3
|
+
id: string;
|
4
|
+
symbol: string;
|
5
|
+
name: string;
|
6
|
+
}[]>;
|
7
|
+
static findMarkets(ids?: string[]): Promise<{
|
8
|
+
id: string;
|
9
|
+
symbol: string;
|
10
|
+
name: string;
|
11
|
+
image: string;
|
12
|
+
current_price: number;
|
13
|
+
}[]>;
|
14
|
+
static createPriceSourceForSymbolIfMissing(symbol: string, ticker: string): Promise<void>;
|
15
|
+
static fillTokensWithCoingeckoData(): Promise<void>;
|
16
|
+
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import { CacheService } from "@/modules/v4/cache";
|
2
|
+
import { PriceService } from "@/modules/v4/price/price.service";
|
3
|
+
import { log } from "@/utils/logger";
|
4
|
+
import { NETWORK_LABELS } from "@sdk";
|
5
|
+
import { TTLPresets } from "../cache/cache.model";
|
6
|
+
import { TokenService } from "../token/token.service";
|
7
|
+
import { CoingeckoRepository } from "./coingecko.repository";
|
8
|
+
export class CoingeckoService {
|
9
|
+
static findList() {
|
10
|
+
return CacheService.wrap(TTLPresets.HOUR_1, CoingeckoRepository.findList);
|
11
|
+
}
|
12
|
+
static findMarkets(ids) {
|
13
|
+
return CacheService.wrap(TTLPresets.MIN_5, CoingeckoRepository.findMarkets, ids);
|
14
|
+
}
|
15
|
+
static async createPriceSourceForSymbolIfMissing(symbol, ticker) {
|
16
|
+
try {
|
17
|
+
await PriceService.getPriceSourceBySymbol(symbol);
|
18
|
+
}
|
19
|
+
catch {
|
20
|
+
await PriceService.createPriceSource({
|
21
|
+
symbol: symbol,
|
22
|
+
method: "COINGECKO",
|
23
|
+
args: {
|
24
|
+
ticker,
|
25
|
+
},
|
26
|
+
});
|
27
|
+
log.info(`added coingecko price source for token ${symbol}: ${ticker}`);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
static async fillTokensWithCoingeckoData() {
|
31
|
+
// 1 - Get coingecko token list
|
32
|
+
const coingeckoData = CoingeckoService.findList();
|
33
|
+
// 2 - Find tokens with missing prices and try to add the sources
|
34
|
+
const missingPriceTokens = await TokenService.findMany({ missingPrice: true });
|
35
|
+
for (const token of missingPriceTokens) {
|
36
|
+
const coingeckoToken = (await coingeckoData).find(t => t.symbol === token.symbol && t.name === token.name);
|
37
|
+
if (!!coingeckoToken) {
|
38
|
+
await CoingeckoService.createPriceSourceForSymbolIfMissing(token.symbol, coingeckoToken.id);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
// 3 - Find tokens with missing logos and gather their ids
|
42
|
+
const missingIconsTokens = await TokenService.findMany({ missingIcons: true });
|
43
|
+
const coingeckoIds = [];
|
44
|
+
for (const token of missingIconsTokens) {
|
45
|
+
const coingeckoToken = (await coingeckoData).find(t => t.symbol === token.symbol && t.name === token.name);
|
46
|
+
if (!!coingeckoToken) {
|
47
|
+
coingeckoIds.push(coingeckoToken.id);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
// Avoid rate limits, wait 2 min
|
51
|
+
await new Promise(resolve => setTimeout(resolve, 120_000));
|
52
|
+
// 4 - Get images and fill them
|
53
|
+
const coingeckoMarkets = await CoingeckoService.findMarkets(coingeckoIds);
|
54
|
+
for (const market of coingeckoMarkets) {
|
55
|
+
for (const token of missingIconsTokens) {
|
56
|
+
if (token.symbol === market.symbol && token.name === market.name) {
|
57
|
+
await TokenService.update(token.id, {
|
58
|
+
icon: market.image,
|
59
|
+
});
|
60
|
+
log.info(`updated token ${token.symbol} on ${NETWORK_LABELS[token.chainId]} with icon ${market.image}`);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
@@ -2065,6 +2065,7 @@ export declare const v4: Elysia<"/v4", false, {
|
|
2065
2065
|
isNative?: boolean | undefined;
|
2066
2066
|
test?: boolean | undefined;
|
2067
2067
|
missingIcons?: boolean | undefined;
|
2068
|
+
missingPrice?: boolean | undefined;
|
2068
2069
|
};
|
2069
2070
|
headers: unknown;
|
2070
2071
|
response: {
|
@@ -2102,6 +2103,7 @@ export declare const v4: Elysia<"/v4", false, {
|
|
2102
2103
|
isNative?: boolean | undefined;
|
2103
2104
|
test?: boolean | undefined;
|
2104
2105
|
missingIcons?: boolean | undefined;
|
2106
|
+
missingPrice?: boolean | undefined;
|
2105
2107
|
};
|
2106
2108
|
headers: unknown;
|
2107
2109
|
response: {
|
@@ -2139,7 +2141,7 @@ export declare const v4: Elysia<"/v4", false, {
|
|
2139
2141
|
isPoint: boolean;
|
2140
2142
|
isNative: boolean;
|
2141
2143
|
price: number | null;
|
2142
|
-
}
|
2144
|
+
};
|
2143
2145
|
};
|
2144
2146
|
};
|
2145
2147
|
};
|
@@ -2180,20 +2182,6 @@ export declare const v4: Elysia<"/v4", false, {
|
|
2180
2182
|
};
|
2181
2183
|
};
|
2182
2184
|
};
|
2183
|
-
} & {
|
2184
|
-
icons: {
|
2185
|
-
post: {
|
2186
|
-
body: unknown;
|
2187
|
-
params: {};
|
2188
|
-
query: unknown;
|
2189
|
-
headers: {
|
2190
|
-
authorization: string;
|
2191
|
-
};
|
2192
|
-
response: {
|
2193
|
-
200: void;
|
2194
|
-
};
|
2195
|
-
};
|
2196
|
-
};
|
2197
2185
|
} & {
|
2198
2186
|
webhooks: {
|
2199
2187
|
notion: {
|
@@ -156,6 +156,7 @@ export declare const TokenController: Elysia<"/tokens", false, {
|
|
156
156
|
isNative?: boolean | undefined;
|
157
157
|
test?: boolean | undefined;
|
158
158
|
missingIcons?: boolean | undefined;
|
159
|
+
missingPrice?: boolean | undefined;
|
159
160
|
};
|
160
161
|
headers: unknown;
|
161
162
|
response: {
|
@@ -193,6 +194,7 @@ export declare const TokenController: Elysia<"/tokens", false, {
|
|
193
194
|
isNative?: boolean | undefined;
|
194
195
|
test?: boolean | undefined;
|
195
196
|
missingIcons?: boolean | undefined;
|
197
|
+
missingPrice?: boolean | undefined;
|
196
198
|
};
|
197
199
|
headers: unknown;
|
198
200
|
response: {
|
@@ -230,7 +232,7 @@ export declare const TokenController: Elysia<"/tokens", false, {
|
|
230
232
|
isPoint: boolean;
|
231
233
|
isNative: boolean;
|
232
234
|
price: number | null;
|
233
|
-
}
|
235
|
+
};
|
234
236
|
};
|
235
237
|
};
|
236
238
|
};
|
@@ -271,20 +273,6 @@ export declare const TokenController: Elysia<"/tokens", false, {
|
|
271
273
|
};
|
272
274
|
};
|
273
275
|
};
|
274
|
-
} & {
|
275
|
-
icons: {
|
276
|
-
post: {
|
277
|
-
body: unknown;
|
278
|
-
params: {};
|
279
|
-
query: unknown;
|
280
|
-
headers: {
|
281
|
-
authorization: string;
|
282
|
-
};
|
283
|
-
response: {
|
284
|
-
200: void;
|
285
|
-
};
|
286
|
-
};
|
287
|
-
};
|
288
276
|
} & {
|
289
277
|
webhooks: {
|
290
278
|
notion: {
|
@@ -92,11 +92,6 @@ export const TokenController = new Elysia({ prefix: "/tokens", detail: { tags: [
|
|
92
92
|
headers: AuthorizationHeadersDto,
|
93
93
|
beforeHandle: BackOfficeGuard,
|
94
94
|
detail: { hide: true },
|
95
|
-
})
|
96
|
-
.post("/icons", async () => await TokenService.tryToFillWithCoingeckoIcons(), {
|
97
|
-
headers: AuthorizationHeadersDto,
|
98
|
-
beforeHandle: BackOfficeGuard,
|
99
|
-
detail: { hide: true },
|
100
95
|
})
|
101
96
|
.group("/webhooks", app => {
|
102
97
|
return app.post("/notion", async ({ body }) => TokenService.notionWebhook(body), {
|
@@ -42,6 +42,7 @@ export declare const GetTokenQueryDto: import("@sinclair/typebox").TObject<{
|
|
42
42
|
verified: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
43
43
|
test: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
44
44
|
missingIcons: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
45
|
+
missingPrice: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
45
46
|
}>;
|
46
47
|
export declare const TokenDto: import("@sinclair/typebox").TObject<{
|
47
48
|
address: import("@sinclair/typebox").TString;
|
@@ -31,6 +31,7 @@ export const GetTokenQueryDto = t.Object({
|
|
31
31
|
verified: t.Optional(t.Boolean()),
|
32
32
|
test: t.Optional(t.Boolean()),
|
33
33
|
missingIcons: t.Optional(t.Boolean()),
|
34
|
+
missingPrice: t.Optional(t.Boolean()),
|
34
35
|
});
|
35
36
|
export const TokenDto = t.Object({
|
36
37
|
address: t.String(),
|
@@ -30,6 +30,7 @@ export class TokenRepository {
|
|
30
30
|
verified: query.verified ? { equals: query.verified } : undefined,
|
31
31
|
isTest: query.test ? { equals: query.test } : undefined,
|
32
32
|
icon: query.missingIcons ? { equals: "" } : undefined,
|
33
|
+
price: query.missingPrice ? { equals: null } : undefined,
|
33
34
|
},
|
34
35
|
};
|
35
36
|
}
|
@@ -56,7 +56,6 @@ export declare abstract class TokenService {
|
|
56
56
|
balance: bigint;
|
57
57
|
})[]>;
|
58
58
|
static fetchOnChain(token: TokenModel): Promise<Omit<Token["model"], "id">>;
|
59
|
-
static tryToFillWithCoingeckoIcons(): Promise<void>;
|
60
59
|
static fetchManyOnChain(chainId: ChainId, addresses: string[]): Promise<{
|
61
60
|
[address: string]: Omit<{
|
62
61
|
symbol: string;
|
@@ -256,7 +255,7 @@ export declare abstract class TokenService {
|
|
256
255
|
isPoint: boolean;
|
257
256
|
isNative: boolean;
|
258
257
|
price: number | null;
|
259
|
-
}
|
258
|
+
}>;
|
260
259
|
/**
|
261
260
|
* @deprecated Should be useless now that the token list is not used anymore
|
262
261
|
* Get all tokens from https://github.com/AngleProtocol/angle-token-list and override icons from it
|
@@ -10,6 +10,7 @@ import { apiDbClient } from "@db";
|
|
10
10
|
import { Prisma } from "@db/api";
|
11
11
|
import { ChainInteractionService, DistributionCreatorService, NETWORK_LABELS, bigIntToNumber, } from "@sdk";
|
12
12
|
import { getAddress, parseUnits } from "viem";
|
13
|
+
import { CoingeckoService } from "../coingecko/coingecko.service";
|
13
14
|
import { TokenRepository } from "./token.repository";
|
14
15
|
export class TokenService {
|
15
16
|
static hashId(token) {
|
@@ -93,33 +94,6 @@ export class TokenService {
|
|
93
94
|
}, onchainData),
|
94
95
|
};
|
95
96
|
}
|
96
|
-
static async tryToFillWithCoingeckoIcons() {
|
97
|
-
// 1 - Find coingecko price sources
|
98
|
-
let priceSources = await PriceService.findManyPriceSources({ method: "COINGECKO" });
|
99
|
-
// 2 - Find tokens with missing logos
|
100
|
-
const missingIcons = await TokenService.findMany({ missingIcons: true });
|
101
|
-
// 3 - Do the intersection of both
|
102
|
-
priceSources = priceSources.filter(p => !!missingIcons.find(t => t.symbol === p.symbol));
|
103
|
-
log.info(`found ${priceSources.length} tokens with missing icons on coingecko.`);
|
104
|
-
// 4 - Loop through each and try to get the icon
|
105
|
-
for (const priceSource of priceSources) {
|
106
|
-
const coingeckoTicker = priceSource.args?.ticker;
|
107
|
-
if (!!coingeckoTicker) {
|
108
|
-
try {
|
109
|
-
const icon = await TokenRepository.fetchIconFromCoingeckoTicker(coingeckoTicker);
|
110
|
-
if (icon.length > 0) {
|
111
|
-
const res = await TokenRepository.updateMissingIconsPerSymbol(priceSource.symbol, icon);
|
112
|
-
log.info(`updated ${res.count} tokens with icon ${icon} ${priceSource.symbol}`);
|
113
|
-
}
|
114
|
-
}
|
115
|
-
catch (e) {
|
116
|
-
console.error(e);
|
117
|
-
}
|
118
|
-
// Avoid rate limits, wait 1 min
|
119
|
-
await new Promise(resolve => setTimeout(resolve, 60_000));
|
120
|
-
}
|
121
|
-
}
|
122
|
-
}
|
123
97
|
static async fetchManyOnChain(chainId, addresses) {
|
124
98
|
const tokens = {};
|
125
99
|
// Batch onchain calls together when multiples
|
@@ -259,11 +233,11 @@ export class TokenService {
|
|
259
233
|
}
|
260
234
|
catch (err) {
|
261
235
|
if (err instanceof Prisma.PrismaClientKnownRequestError && err.code === "P2025") {
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
236
|
+
return TokenService.format(await TokenService.fillAndCreate({
|
237
|
+
...token,
|
238
|
+
verified: false,
|
239
|
+
icon: "",
|
240
|
+
}));
|
267
241
|
}
|
268
242
|
}
|
269
243
|
throw new HttpError(`Failed to fetch or create token ${token.address} on chain ${token.chainId}.`);
|
@@ -340,14 +314,24 @@ export class TokenService {
|
|
340
314
|
* @param address
|
341
315
|
*/
|
342
316
|
static async fillAndCreate(token) {
|
317
|
+
const id = TokenService.hashId(token);
|
318
|
+
const filledData = await TokenService.fetchOnChain({ address: token.address, chainId: token.chainId });
|
343
319
|
try {
|
344
|
-
const
|
345
|
-
const
|
346
|
-
|
320
|
+
const coingeckoToken = await CoingeckoService.findList();
|
321
|
+
const coingeckoTokenData = coingeckoToken.find(t => t.symbol === filledData.symbol && t.name === filledData.name);
|
322
|
+
if (!!coingeckoTokenData) {
|
323
|
+
await CoingeckoService.createPriceSourceForSymbolIfMissing(filledData.symbol, coingeckoTokenData.id);
|
324
|
+
if (!token.icon || token.icon === "") {
|
325
|
+
const coingeckoIcon = (await CoingeckoService.findMarkets([coingeckoTokenData.id]))[0].image;
|
326
|
+
token.icon = coingeckoIcon;
|
327
|
+
log.info(`completed with coingecko icon: ${coingeckoIcon}`);
|
328
|
+
}
|
329
|
+
}
|
347
330
|
}
|
348
|
-
catch
|
349
|
-
|
331
|
+
catch {
|
332
|
+
log.warn("coingecko token autocompletion failed");
|
350
333
|
}
|
334
|
+
return await TokenRepository.upsert({ ...filledData, ...token, id });
|
351
335
|
}
|
352
336
|
/**
|
353
337
|
* @deprecated Should be useless now that the token list is not used anymore
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|