1 | import * as _ from 'lodash';
|
2 | import { Environments, EnvironmentName } from './v2/environments';
|
3 | import { OfcTokenConfig } from './v2/coins/ofcToken';
|
4 | import { Erc20TokenConfig } from './v2/coins/erc20Token';
|
5 | import { StellarTokenConfig } from './v2/coins/stellarToken';
|
6 | import { CeloTokenConfig } from './v2/coins/celoToken';
|
7 | import { EosTokenConfig } from './v2/coins/eosToken';
|
8 | import { AlgoTokenConfig } from './v2/coins/algoToken';
|
9 | import { coins, Erc20Coin, StellarCoin, OfcCoin, CeloCoin, CoinKind, NetworkType, EosCoin, Networks, AlgoCoin } from '@bitgo/statics';
|
10 |
|
11 | export interface Tokens {
|
12 | bitcoin: {
|
13 | eth: {
|
14 | tokens: Erc20TokenConfig[];
|
15 | };
|
16 | xlm: {
|
17 | tokens: StellarTokenConfig[];
|
18 | };
|
19 | algo: {
|
20 | tokens: AlgoTokenConfig[];
|
21 | };
|
22 | ofc: {
|
23 | tokens: OfcTokenConfig[];
|
24 | };
|
25 | celo: {
|
26 | tokens: CeloTokenConfig[];
|
27 | };
|
28 | eos: {
|
29 | tokens: EosTokenConfig[];
|
30 | };
|
31 | };
|
32 | testnet: {
|
33 | eth: {
|
34 | tokens: Erc20TokenConfig[];
|
35 | };
|
36 | xlm: {
|
37 | tokens: StellarTokenConfig[];
|
38 | };
|
39 | algo: {
|
40 | tokens: AlgoTokenConfig[];
|
41 | };
|
42 | ofc: {
|
43 | tokens: OfcTokenConfig[];
|
44 | };
|
45 | celo: {
|
46 | tokens: CeloTokenConfig[];
|
47 | };
|
48 | eos: {
|
49 | tokens: EosTokenConfig[];
|
50 | }
|
51 | };
|
52 | }
|
53 |
|
54 |
|
55 | const formattedErc20Tokens = coins.reduce((acc: Erc20TokenConfig[], coin) => {
|
56 | if (coin instanceof Erc20Coin) {
|
57 | let baseCoin: string;
|
58 | switch (coin.network) {
|
59 | case Networks.main.ethereum:
|
60 | baseCoin = 'eth';
|
61 | break;
|
62 | case Networks.test.kovan:
|
63 | baseCoin = 'teth';
|
64 | break;
|
65 | case Networks.test.goerli:
|
66 | baseCoin = 'gteth';
|
67 | break;
|
68 | default:
|
69 | throw new Error(`Erc20 token ${coin.name} has an unsupported network`);
|
70 | }
|
71 |
|
72 | acc.push({
|
73 | type: coin.name,
|
74 | coin: baseCoin,
|
75 | network: coin.network.type === NetworkType.MAINNET ? 'Mainnet' : 'Testnet',
|
76 | name: coin.fullName,
|
77 | tokenContractAddress: coin.contractAddress.toString().toLowerCase(),
|
78 | decimalPlaces: coin.decimalPlaces,
|
79 | });
|
80 | }
|
81 | return acc;
|
82 | }, []);
|
83 |
|
84 | export const ethGasConfigs = {
|
85 | minimumGasPrice: 1000000000,
|
86 | defaultGasPrice: 20000000000,
|
87 | maximumGasPrice: 2500000000000,
|
88 | defaultGasLimit: 500000,
|
89 | defaultGasLimitTokenSend: 1000000,
|
90 | minimumGasLimit: 30000,
|
91 | maximumGasLimit: 20000000,
|
92 | };
|
93 |
|
94 | const formattedStellarTokens = coins.reduce((acc: StellarTokenConfig[], coin) => {
|
95 | if (coin instanceof StellarCoin) {
|
96 | acc.push({
|
97 | type: coin.name,
|
98 | coin: coin.network.type === NetworkType.MAINNET ? 'xlm' : 'txlm',
|
99 | network: coin.network.type === NetworkType.MAINNET ? 'Mainnet' : 'Testnet',
|
100 | name: coin.fullName,
|
101 | decimalPlaces: coin.decimalPlaces,
|
102 | });
|
103 | }
|
104 | return acc;
|
105 | }, []);
|
106 |
|
107 |
|
108 | const formattedAlgoTokens = coins.reduce((acc: AlgoTokenConfig[], coin) => {
|
109 | if (coin instanceof AlgoCoin) {
|
110 | acc.push({
|
111 | type: coin.name,
|
112 | coin: coin.network.type === NetworkType.MAINNET ? 'algo' : 'talgo',
|
113 | network: coin.network.type === NetworkType.MAINNET ? 'Mainnet' : 'Testnet',
|
114 | name: coin.fullName,
|
115 | decimalPlaces: coin.decimalPlaces,
|
116 | });
|
117 | }
|
118 | return acc;
|
119 | }, []);
|
120 |
|
121 |
|
122 | const formattedOfcCoins = coins.reduce((acc: OfcTokenConfig[], coin) => {
|
123 | if (coin instanceof OfcCoin) {
|
124 | acc.push({
|
125 | type: coin.name,
|
126 | coin: 'ofc',
|
127 | backingCoin: coin.asset,
|
128 | name: coin.fullName,
|
129 | decimalPlaces: coin.decimalPlaces,
|
130 | isFiat: coin.kind === CoinKind.FIAT,
|
131 | });
|
132 | }
|
133 | return acc;
|
134 | }, []);
|
135 |
|
136 | const formattedCeloTokens = coins.reduce((acc: CeloTokenConfig[], coin) => {
|
137 | if (coin instanceof CeloCoin) {
|
138 | acc.push({
|
139 | type: coin.name,
|
140 | coin: coin.network.type === NetworkType.MAINNET ? 'celo' : 'tcelo',
|
141 | network: coin.network.type === NetworkType.MAINNET ? 'Mainnet' : 'Testnet',
|
142 | name: coin.fullName,
|
143 | tokenContractAddress: coin.contractAddress.toString().toLowerCase(),
|
144 | decimalPlaces: coin.decimalPlaces,
|
145 | });
|
146 | }
|
147 | return acc;
|
148 | }, []);
|
149 |
|
150 | const formattedEosTokens = coins.reduce((acc: EosTokenConfig[], coin) => {
|
151 | if (coin instanceof EosCoin) {
|
152 | acc.push({
|
153 | type: coin.name,
|
154 | coin: coin.network.type === NetworkType.MAINNET ? 'eos' : 'teos',
|
155 | network: coin.network.type === NetworkType.MAINNET ? 'Mainnet' : 'Testnet',
|
156 | name: coin.fullName,
|
157 | tokenContractAddress: coin.contractName.toString().toLowerCase(),
|
158 | decimalPlaces: coin.decimalPlaces,
|
159 | });
|
160 | }
|
161 | return acc;
|
162 | }, []);
|
163 |
|
164 | export const tokens: Tokens = {
|
165 |
|
166 | bitcoin: {
|
167 | eth: {
|
168 | tokens: formattedErc20Tokens.filter(token => token.network === 'Mainnet'),
|
169 | },
|
170 | xlm: {
|
171 | tokens: formattedStellarTokens.filter(token => token.network === 'Mainnet'),
|
172 | },
|
173 | algo: {
|
174 | tokens: formattedAlgoTokens.filter(token => token.network === 'Mainnet'),
|
175 | },
|
176 | ofc: {
|
177 | tokens: formattedOfcCoins.filter(token => coins.get(token.type).network.type === NetworkType.MAINNET),
|
178 | },
|
179 | celo: {
|
180 | tokens: formattedCeloTokens.filter(token => token.network === 'Mainnet'),
|
181 | },
|
182 | eos: {
|
183 | tokens: formattedEosTokens.filter(token => token.network === 'Mainnet'),
|
184 | },
|
185 | },
|
186 |
|
187 | testnet: {
|
188 | eth: {
|
189 | tokens: formattedErc20Tokens.filter(token => token.network === 'Testnet'),
|
190 | },
|
191 | xlm: {
|
192 | tokens: formattedStellarTokens.filter(token => token.network === 'Testnet'),
|
193 | },
|
194 | algo: {
|
195 | tokens: formattedAlgoTokens.filter(token => token.network === 'Testnet'),
|
196 | },
|
197 | ofc: {
|
198 | tokens: formattedOfcCoins.filter(token => coins.get(token.type).network.type === NetworkType.TESTNET),
|
199 | },
|
200 | celo: {
|
201 | tokens: formattedCeloTokens.filter(token => token.network === 'Testnet'),
|
202 | },
|
203 | eos: {
|
204 | tokens: formattedEosTokens.filter(token => token.network === 'Testnet'),
|
205 | },
|
206 | },
|
207 | };
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 | const verifyTokens = function (tokens) {
|
214 | const verifiedTokens = {};
|
215 | _.forEach(tokens, function (token) {
|
216 | if (verifiedTokens[token.type]) {
|
217 | throw new Error('token : ' + token.type + ' duplicated.');
|
218 | }
|
219 | verifiedTokens[token.type] = true;
|
220 |
|
221 | if (token.tokenContractAddress && token.tokenContractAddress !== _.toLower(token.tokenContractAddress)) {
|
222 | throw new Error('token contract: ' + token.type + ' is not all lower case: ' + token.tokenContractAddress);
|
223 | }
|
224 | });
|
225 | return verifiedTokens;
|
226 | };
|
227 |
|
228 | const mainnetErc20Tokens = verifyTokens(tokens.bitcoin.eth.tokens);
|
229 | const mainnetStellarTokens = verifyTokens(tokens.bitcoin.xlm.tokens);
|
230 | export const mainnetTokens = _.assign({}, mainnetErc20Tokens, mainnetStellarTokens);
|
231 |
|
232 | const testnetErc20Tokens = verifyTokens(tokens.testnet.eth.tokens);
|
233 | const testnetStellarTokens = verifyTokens(tokens.testnet.xlm.tokens);
|
234 | export const testnetTokens = _.assign({}, testnetErc20Tokens, testnetStellarTokens);
|
235 |
|
236 |
|
237 | export const defaults = {
|
238 | maxFee: 0.1e8,
|
239 | maxFeeRate: 1000000,
|
240 | minFeeRate: 5000,
|
241 | fallbackFeeRate: 50000,
|
242 | minOutputSize: 2730,
|
243 | minInstantFeeRate: 10000,
|
244 | bitgoEthAddress: '0x0f47ea803926926f299b7f1afc8460888d850f47',
|
245 | };
|
246 |
|
247 |
|
248 |
|
249 | export const supportedCrossChainRecoveries = {
|
250 | btc: ['bch', 'ltc', 'bsv'],
|
251 | bch: ['btc', 'ltc', 'bsv'],
|
252 | ltc: ['btc', 'bch', 'bsv'],
|
253 | bsv: ['btc', 'ltc', 'bch'],
|
254 | };
|
255 |
|
256 | export type KrsProvider = {
|
257 | feeType: 'flatUsd';
|
258 | feeAmount: number;
|
259 | supportedCoins: string[];
|
260 | feeAddresses?: Record<string, string>
|
261 | }
|
262 |
|
263 |
|
264 | export const krsProviders: Record<string, KrsProvider> = {
|
265 | keyternal: {
|
266 | feeType: 'flatUsd',
|
267 | feeAmount: 99,
|
268 | supportedCoins: ['btc', 'eth'],
|
269 | feeAddresses: {
|
270 | btc: '',
|
271 | },
|
272 | },
|
273 | bitgoKRSv2: {
|
274 | feeType: 'flatUsd',
|
275 | feeAmount: 0,
|
276 | supportedCoins: ['btc', 'eth'],
|
277 | },
|
278 | dai: {
|
279 | feeType: 'flatUsd',
|
280 | feeAmount: 0,
|
281 | supportedCoins: ['btc', 'eth', 'xlm', 'xrp', 'dash', 'zec', 'ltc', 'bch', 'bsv', 'bcha'],
|
282 | },
|
283 | };
|
284 |
|
285 | export const coinGeckoBaseUrl = 'https://api.coingecko.com/api/v3/';
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | export const defaultConstants = (env: EnvironmentName) => {
|
296 | if (Environments[env] === undefined) {
|
297 | throw Error(`invalid environment ${env}`);
|
298 | }
|
299 |
|
300 | const network = Environments[env].network;
|
301 | return _.merge({}, defaults, tokens[network]);
|
302 | };
|