forked from d-EURO/api
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi.config.ts
More file actions
155 lines (141 loc) · 4.83 KB
/
api.config.ts
File metadata and controls
155 lines (141 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import { Address, Chain, createPublicClient, http, zeroAddress } from 'viem';
import { ADDRESS } from '@juicedollar/jusd';
import { Logger } from '@nestjs/common';
import { mainnet, testnet } from 'chains';
import * as dotenv from 'dotenv';
dotenv.config();
// Verify environment
const isMainnet = process.env.CONFIG_CHAIN === 'mainnet';
if (isMainnet && process.env.RPC_URL_MAINNET === undefined) throw new Error('RPC_URL_MAINNET not available');
if (!isMainnet && process.env.RPC_URL_TESTNET === undefined) throw new Error('RPC_URL_TESTNET not available');
// COINGECKO_BASE_URL is the origin the api calls — typically the in-cluster
// pricing-proxy (https://github.com/DFXswiss/pricing-proxy), but any
// CoinGecko-compatible host works. COINGECKO_API_KEY is optional and is
// only attached as `x-cg-pro-api-key` on every request when set (proxy mode
// leaves it unset because the proxy injects its own key).
if (!process.env.COINGECKO_BASE_URL) {
throw new Error('COINGECKO_BASE_URL is not set');
}
// Config type
export type ConfigType = {
app: string;
indexer: string;
indexerFallback: string;
coingeckoBaseUrl: string;
coingeckoApiKey: string | undefined;
chain: Chain;
network: {
mainnet: string;
testnet: string;
};
telegram: {
botToken: string;
groupsJson: string;
imagesDir: string;
} | null;
twitter: {
accessToken: string;
accessSecret: string;
appKey: string;
appSecret: string;
imagesDir: string;
} | null;
};
// Create config
export const CONFIG: ConfigType = {
app: process.env.CONFIG_APP_URL,
indexer: process.env.CONFIG_INDEXER_URL,
indexerFallback: process.env.CONFIG_INDEXER_FALLBACK_URL,
coingeckoBaseUrl: process.env.COINGECKO_BASE_URL,
coingeckoApiKey: process.env.COINGECKO_API_KEY || undefined,
chain: isMainnet ? mainnet : testnet,
network: {
mainnet: process.env.RPC_URL_MAINNET,
testnet: process.env.RPC_URL_TESTNET,
},
telegram: process.env.TELEGRAM_BOT_TOKEN
? {
botToken: process.env.TELEGRAM_BOT_TOKEN,
groupsJson: process.env.TELEGRAM_GROUPS_JSON,
imagesDir: process.env.TELEGRAM_IMAGES_DIR,
}
: null,
twitter: process.env.TWITTER_CLIENT_APP_KEY
? {
appKey: process.env.TWITTER_CLIENT_APP_KEY,
appSecret: process.env.TWITTER_CLIENT_APP_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN,
accessSecret: process.env.TWITTER_ACCESS_SECRET,
imagesDir: process.env.TWITTER_IMAGES_DIR,
}
: null,
};
const SENSITIVE_KEYS = new Set<string>([
'coingeckoApiKey',
'network.mainnet',
'network.testnet',
'telegram.botToken',
'twitter.appKey',
'twitter.appSecret',
'twitter.accessToken',
'twitter.accessSecret',
]);
function redactConfig<T>(config: T): T {
return walkRedact(config, '') as T;
}
function walkRedact(value: unknown, path: string): unknown {
if (value && typeof value === 'object' && !Array.isArray(value)) {
return Object.fromEntries(
Object.entries(value as Record<string, unknown>).map(([key, val]) => {
const childPath = path ? `${path}.${key}` : key;
if (SENSITIVE_KEYS.has(childPath) && val) return [key, '***'];
return [key, walkRedact(val, childPath)];
})
);
}
return value;
}
export function logConfig() {
const logger = new Logger('ApiConfig');
logger.log(`Starting API with this config:`);
logger.log(JSON.stringify(redactConfig(CONFIG)));
}
// Refer to https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
process.env.NTBA_FIX_350 = 'true';
// VIEM CONFIG
export const VIEM_CHAIN = CONFIG.chain;
export const VIEM_CONFIG = createPublicClient({
chain: VIEM_CHAIN,
transport: http(isMainnet ? CONFIG.network.mainnet : CONFIG.network.testnet),
batch: {
multicall: {
wait: 200,
},
},
});
// COINGECKO CLIENT
//
// Calls go to whatever `COINGECKO_BASE_URL` points at. When the optional
// `COINGECKO_API_KEY` is set, it is attached as the `x-cg-pro-api-key`
// header — orthogonal to the base URL, never a fallback. The recommended
// deployment is the in-cluster pricing-proxy
// (https://github.com/DFXswiss/pricing-proxy), which injects its own key
// and leaves COINGECKO_API_KEY unset on every consumer.
export const COINGECKO_CLIENT = (query: string) => {
const headers: Record<string, string> = { accept: 'application/json' };
if (CONFIG.coingeckoApiKey) {
headers['x-cg-pro-api-key'] = CONFIG.coingeckoApiKey;
}
return fetch(`${CONFIG.coingeckoBaseUrl}${query}`, { headers });
};
export const PROTOCOL_STABLECOIN_SYMBOL = 'JUSD';
export const PROTOCOL_STABLECOIN_NAME = 'Juice Dollar';
export const POOL_SHARES_SYMBOL = 'JUICE';
// Contract addresses for the active chain
export const ADDR = ADDRESS[CONFIG.chain.id];
export function isDeployed(addr: string | undefined): addr is Address {
return !!addr && addr !== zeroAddress;
}
export function isV3Hub(hubAddress: Address): boolean {
return isDeployed(ADDR.mintingHub) && hubAddress.toLowerCase() === ADDR.mintingHub.toLowerCase();
}