@bitpay-labs/bitcore-wallet-service 11.5.2 → 11.6.2
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/package.json +4 -4
- package/src/externalservices/coingecko.ts +448 -368
- package/src/lib/common/utils.ts +37 -32
- package/src/lib/tss.ts +18 -10
- package/test/integration/externalservices/coinGecko.test.ts +811 -156
- package/test/utils.test.ts +5 -0
- package/ts_build/package.json +3 -3
- package/ts_build/src/externalservices/coingecko.d.ts +24 -20
- package/ts_build/src/externalservices/coingecko.d.ts.map +1 -1
- package/ts_build/src/externalservices/coingecko.js +356 -306
- package/ts_build/src/externalservices/coingecko.js.map +1 -1
- package/ts_build/src/lib/common/index.d.ts +2 -2
- package/ts_build/src/lib/common/utils.d.ts +2 -2
- package/ts_build/src/lib/common/utils.d.ts.map +1 -1
- package/ts_build/src/lib/common/utils.js +28 -29
- package/ts_build/src/lib/common/utils.js.map +1 -1
- package/ts_build/src/lib/tss.d.ts.map +1 -1
- package/ts_build/src/lib/tss.js +2 -10
- package/ts_build/src/lib/tss.js.map +1 -1
- package/ts_build/test/integration/externalservices/coinGecko.test.d.ts +1 -1
- package/ts_build/test/integration/externalservices/coinGecko.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/coinGecko.test.js +710 -149
- package/ts_build/test/integration/externalservices/coinGecko.test.js.map +1 -1
- package/ts_build/test/utils.test.js +4 -0
- package/ts_build/test/utils.test.js.map +1 -1
- package/scripts/delme.ts +0 -468
- package/scripts/findEmail.js +0 -32
- package/scripts/getSolStats2.js +0 -81
- package/scripts/walletStats.js +0 -290
- package/src/types/emailservice.d.ts +0 -11
- package/src/types/notifications.d.ts +0 -8
- package/src/types/pushnotificationservice.d.ts +0 -51
- package/ts_build/scripts/delme.d.ts +0 -2
- package/ts_build/scripts/delme.d.ts.map +0 -1
- package/ts_build/scripts/delme.js +0 -453
- package/ts_build/scripts/delme.js.map +0 -1
package/scripts/walletStats.js
DELETED
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import os from 'os';
|
|
5
|
-
import readline from 'readline';
|
|
6
|
-
import * as CWC from '@bitpay-labs/crypto-wallet-core';
|
|
7
|
-
import Moralis from 'moralis';
|
|
8
|
-
import request from 'request-promise-native';
|
|
9
|
-
import { Storage } from '../../ts_build/src';
|
|
10
|
-
import config from '../../ts_build/src/config';
|
|
11
|
-
import { WalletService } from '../../ts_build/src/lib/server';
|
|
12
|
-
|
|
13
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
14
|
-
|
|
15
|
-
let shuttingDown = false;
|
|
16
|
-
process.on('SIGINT', function() {
|
|
17
|
-
if (shuttingDown) {
|
|
18
|
-
console.log('Forced exit');
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
shuttingDown = true;
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
function usage(errMsg) {
|
|
25
|
-
console.log('USAGE: ./walletStats.js [options]');
|
|
26
|
-
console.log('OPTIONS:');
|
|
27
|
-
console.log(' --start <value> Start month (MM/YYYY) (default: last month)');
|
|
28
|
-
console.log(' --end <value> End month (MM/YYYY) - inclusive (default: last month)');
|
|
29
|
-
console.log(' --chain <value> Chain (default: all)');
|
|
30
|
-
console.log(' --network <value> Network (default: livenet)');
|
|
31
|
-
console.log(' --out <value> Output file (default: stats-<date>.json)');
|
|
32
|
-
console.log(' --config Only change the sleep config file (walletStats.config.json) and exit');
|
|
33
|
-
console.log(' --sleep <value> Sleep time in milliseconds between iterations. Default: 250');
|
|
34
|
-
console.log(' --every <value> Sleep for --sleep milliseconds every --every loop iteration. Default: 100');
|
|
35
|
-
console.log(' ');
|
|
36
|
-
if (errMsg) {
|
|
37
|
-
console.log('\nERROR: ' + errMsg);
|
|
38
|
-
}
|
|
39
|
-
process.exit();
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const args = process.argv.slice(2);
|
|
43
|
-
|
|
44
|
-
if (args.includes('--help') || args.includes('-h')) {
|
|
45
|
-
usage();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const sleepIdx = args.indexOf('--sleep');
|
|
50
|
-
let sleepMs = sleepIdx > -1 ? parseInt(args[sleepIdx + 1]) : 250;
|
|
51
|
-
const everyIdx = args.indexOf('--every');
|
|
52
|
-
let nSleep = everyIdx > -1 ? parseInt(args[everyIdx + 1]) : 100;
|
|
53
|
-
fs.writeFileSync('./walletStats.config.json', JSON.stringify({ sleepMs, nSleep }, null, 2));
|
|
54
|
-
if (args.includes('--config')) {
|
|
55
|
-
console.log('Config updated.');
|
|
56
|
-
process.exit(0);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const yestermonth = new Date();
|
|
61
|
-
yestermonth.setUTCMonth(yestermonth.getUTCMonth() - 1); // Default to last month
|
|
62
|
-
const lastMonth = (yestermonth.getUTCMonth() + 1).toString().padStart(2, '0');
|
|
63
|
-
const year = yestermonth.getUTCFullYear();
|
|
64
|
-
|
|
65
|
-
const startIdx = args.indexOf('--start');
|
|
66
|
-
if (startIdx > -1 && (!args[startIdx + 1] || !args[startIdx + 1].match(/^(0[1-9]|1[0-2])\/20[0-9]{2}$/))) {
|
|
67
|
-
usage('Invalid start date format. Use MM/YYYY');
|
|
68
|
-
}
|
|
69
|
-
const start = startIdx > -1 ? args[startIdx + 1] : `${lastMonth}/${year}`;
|
|
70
|
-
|
|
71
|
-
const endIdx = args.indexOf('--end');
|
|
72
|
-
if (endIdx > -1 && (!args[endIdx + 1] || !args[endIdx + 1].match(/^(0[1-9]|1[0-2])\/20[0-9]{2}$/))) {
|
|
73
|
-
usage('Invalid end date format. Use MM/YYYY');
|
|
74
|
-
}
|
|
75
|
-
const end = endIdx > -1 ? args[endIdx + 1] : `${lastMonth}/${year}`;
|
|
76
|
-
|
|
77
|
-
const chainIdx = args.indexOf('--chain');
|
|
78
|
-
const chain = (chainIdx > -1 && args[chainIdx + 1]?.toLowerCase()) || null;
|
|
79
|
-
|
|
80
|
-
const networkIdx = args.indexOf('--network');
|
|
81
|
-
const network = (networkIdx > -1 && args[networkIdx + 1]?.toLowerCase()) || 'livenet';
|
|
82
|
-
|
|
83
|
-
const outIdx = args.indexOf('--out');
|
|
84
|
-
let outFile = (outIdx > -1 && args[outIdx + 1]) || `stats-${new Date().toISOString()}.json`;
|
|
85
|
-
|
|
86
|
-
if (outFile.startsWith('~')) {
|
|
87
|
-
outFile = outFile.replace('~', os.homedir());
|
|
88
|
-
}
|
|
89
|
-
if (outFile.startsWith('$HOME')) {
|
|
90
|
-
outFile = outFile.replace('$HOME', os.homedir());
|
|
91
|
-
}
|
|
92
|
-
if (!outFile.startsWith('/') && !outFile.startsWith('./') && !outFile.startsWith('../')) {
|
|
93
|
-
outFile = __dirname + '/' + outFile;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const tokenChainMap = {
|
|
97
|
-
WBTC: 'btc',
|
|
98
|
-
WETH: 'eth',
|
|
99
|
-
MATIC: 'matic'
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const storage = new Storage();
|
|
103
|
-
storage.connect(config.storageOpts, async (err) => {
|
|
104
|
-
if (err) {
|
|
105
|
-
console.log(err);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
await new Promise((r, j) => WalletService.initialize(
|
|
109
|
-
{
|
|
110
|
-
...config,
|
|
111
|
-
storage,
|
|
112
|
-
messageBroker: { onMessage: () => {} },
|
|
113
|
-
fiatRateService: {}
|
|
114
|
-
},
|
|
115
|
-
(err) => {
|
|
116
|
-
if (err) return j(err);
|
|
117
|
-
return r();
|
|
118
|
-
}
|
|
119
|
-
));
|
|
120
|
-
const walletService = new WalletService();
|
|
121
|
-
|
|
122
|
-
function done(err) {
|
|
123
|
-
if (err) { console.log(err); }
|
|
124
|
-
rl.close();
|
|
125
|
-
WalletService.shutDown((err) => {
|
|
126
|
-
if (err) { console.log(err); }
|
|
127
|
-
fs.rmSync('./walletStats.config.json');
|
|
128
|
-
console.log('done');
|
|
129
|
-
});
|
|
130
|
-
// storage.disconnect(() => { console.log('done'); });
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
// await Moralis.start({
|
|
135
|
-
// apiKey: config.moralis.apiKey
|
|
136
|
-
// });
|
|
137
|
-
// Get all wallets
|
|
138
|
-
const walletCnt = await storage.db.collection(Storage.collections.WALLETS).count({});
|
|
139
|
-
const walletStream = storage.db.collection(Storage.collections.WALLETS).find({});
|
|
140
|
-
|
|
141
|
-
console.log(` Found ${Intl.NumberFormat().format(walletCnt)} total wallets to scan`);
|
|
142
|
-
console.log(` Output file: ${outFile}`);
|
|
143
|
-
const ans = await new Promise(r => rl.question('Would you like to continue? (Y/n): ', r));
|
|
144
|
-
if (ans?.toLowerCase() === 'n') {
|
|
145
|
-
return done('Good bye.');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const retval = {};
|
|
149
|
-
let count = 0;
|
|
150
|
-
let relevantWallets = 0;
|
|
151
|
-
let perfTime = Date.now();
|
|
152
|
-
let perfCnt = 0;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
for await (const wallet of walletStream) {
|
|
156
|
-
if (shuttingDown) {
|
|
157
|
-
throw new Error('Interrupted by user');
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
count++;
|
|
161
|
-
if (count % nSleep === 0) {
|
|
162
|
-
const cntDiff = count - perfCnt;
|
|
163
|
-
const timeDiff = Date.now() - perfTime;
|
|
164
|
-
const rate = (cntDiff / timeDiff * 1000).toFixed(2); // wallets per second
|
|
165
|
-
process.stdout.write(`Processed ${(count / walletCnt * 100).toFixed(4)}% wallets (${count} | ${relevantWallets}) - ${rate} wallets/sec\r`); // shows how fast things are working
|
|
166
|
-
await new Promise(resolve => setTimeout(resolve, sleepMs)); // cooldown
|
|
167
|
-
({ nSleep, sleepMs } = JSON.parse(fs.readFileSync('./walletStats.config.json', 'utf8'))); // reload config
|
|
168
|
-
perfTime = Date.now();
|
|
169
|
-
perfCnt = count;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const wChain = wallet.chain || wallet.coin || 'btc';
|
|
173
|
-
const [smonth, syear] = start.split('/');
|
|
174
|
-
const startDate = new Date(`${syear}-${smonth}-01T00:00:00Z`);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (wallet.status !== 'complete') continue; // skip incomplete wallets
|
|
178
|
-
if (!wallet.beAuthPrivateKey2) continue; // skip too old wallets
|
|
179
|
-
if (chain && (
|
|
180
|
-
(wallet.chain?.toLowerCase() !== chain && wallet.coin?.toLowerCase() !== chain) ||
|
|
181
|
-
(!wallet.coin && chain !== 'btc') // legacy wallets default to btc
|
|
182
|
-
)) continue; // skip non-matching chain
|
|
183
|
-
if (wallet.network?.toLowerCase() !== network) continue;
|
|
184
|
-
|
|
185
|
-
relevantWallets++;
|
|
186
|
-
|
|
187
|
-
const [emonth, eyear] = end.split('/');
|
|
188
|
-
const endDate = new Date(`${eyear}-${emonth}-01T00:00:00Z`);
|
|
189
|
-
|
|
190
|
-
const tokenOpts = CWC.Constants[`${wChain.toUpperCase()}_TOKEN_OPTS`];
|
|
191
|
-
const dateKey = startDate.toISOString().split('T')[0];
|
|
192
|
-
if (!retval[dateKey]) {
|
|
193
|
-
retval[dateKey] = {};
|
|
194
|
-
}
|
|
195
|
-
if (!retval[dateKey][wChain]) {
|
|
196
|
-
retval[dateKey][wChain] = { wallets: 0n, totalBalance: 0n };
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
const bc = walletService._getBlockchainExplorer(wChain, wallet.network);
|
|
201
|
-
const client = bc._getAuthClient(wallet);
|
|
202
|
-
// todo: is there a quick check to see if the wallet has _any_ activity?
|
|
203
|
-
while (startDate <= endDate) {
|
|
204
|
-
let balance = 0;
|
|
205
|
-
if (['btc', 'bch', 'ltc', 'doge', 'xrp'].includes(wChain)) {
|
|
206
|
-
const query = '';
|
|
207
|
-
const apiUrl = `${client.baseUrl}/wallet/${wallet.beAuthPublicKey2}/balance/${startDate.toISOString()}`;
|
|
208
|
-
const url = apiUrl + query;
|
|
209
|
-
const signature = client.sign({ method: 'GET', url });
|
|
210
|
-
const response = await request.get(url, {
|
|
211
|
-
headers: { 'x-signature': signature },
|
|
212
|
-
json: true
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
if (!response.balance) {
|
|
216
|
-
startDate.setUTCMonth(startDate.getUTCMonth() + 1);
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
balance = response.balance;
|
|
220
|
-
} else if (wChain === 'sol') {
|
|
221
|
-
// todo
|
|
222
|
-
continue;
|
|
223
|
-
} else { // EVM
|
|
224
|
-
const CHAIN_IDS = CWC.Constants.EVM_CHAIN_NETWORK_TO_CHAIN_ID;
|
|
225
|
-
const chainKey = `${wChain.toUpperCase()}_${wallet.network === 'livenet' ? 'mainnet' : wallet.network}`;
|
|
226
|
-
if (!CHAIN_IDS[chainKey]) {
|
|
227
|
-
throw new Error(`Unsupported chain/network: ${chainKey}`);
|
|
228
|
-
}
|
|
229
|
-
const chainId = CHAIN_IDS[chainKey];
|
|
230
|
-
|
|
231
|
-
const addresses = await storage.db.collection(Storage.collections.ADDRESSES).find({ walletId: wallet.id, createdOn: { $exists: true } }).toArray();
|
|
232
|
-
if (!addresses[0]) {
|
|
233
|
-
break; // no addresses, skip
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const blkResponse = await Moralis.EvmApi.block.getDateToBlock({
|
|
237
|
-
chain: chainId,
|
|
238
|
-
date: startDate.toISOString()
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const balResponse = await Moralis.EvmApi.wallets.getWalletTokenBalancesPrice({
|
|
242
|
-
chain: chainId,
|
|
243
|
-
toBlock: blkResponse.raw.block,
|
|
244
|
-
excludeSpam: true,
|
|
245
|
-
address: addresses[0].address // assume first address is representative of whole wallet
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
for (const token of balResponse.json.result) {
|
|
249
|
-
if (token.native_token) {
|
|
250
|
-
balance = BigInt(token.balance);
|
|
251
|
-
} else {
|
|
252
|
-
const tokenOpt = tokenOpts[token.token_address.toLowerCase()];
|
|
253
|
-
const tChain = tokenChainMap[tokenOpt?.symbol];
|
|
254
|
-
if (tChain) {
|
|
255
|
-
retval[dateKey][tChain] = retval[dateKey][tChain] || { wallets: 0n, totalBalance: 0n };
|
|
256
|
-
retval[dateKey][tChain].wallets++;
|
|
257
|
-
retval[dateKey][tChain].totalBalance += BigInt(token.balance);
|
|
258
|
-
} else {
|
|
259
|
-
// record unknown/stablecoin token's USD values
|
|
260
|
-
if (!retval[dateKey]['USD']) {
|
|
261
|
-
retval[dateKey]['USD'] = { wallets: 0n, totalBalance: 0n };
|
|
262
|
-
}
|
|
263
|
-
retval[dateKey]['USD'].wallets++;
|
|
264
|
-
retval[dateKey]['USD'].totalBalance += BigInt(Math.round(token.usd_value));
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
retval[dateKey][wChain].wallets++;
|
|
271
|
-
retval[dateKey][wChain].totalBalance += BigInt(balance);
|
|
272
|
-
|
|
273
|
-
startDate.setUTCMonth(startDate.getUTCMonth() + 1);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
fs.writeFileSync(outFile, JSON.stringify(retval, (k, v) => typeof v === 'bigint' ? v.toString() : v, 2));
|
|
277
|
-
} catch (e) {
|
|
278
|
-
console.log(`\nError fetching data for wallet ${wallet.id} (${wChain}/${wallet.network}): ${e.stack}`);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
process.stdout.write('\n');
|
|
283
|
-
|
|
284
|
-
console.log(`Wrote stats for ${relevantWallets} wallets to ${outFile}`);
|
|
285
|
-
|
|
286
|
-
return done();
|
|
287
|
-
} catch (err) {
|
|
288
|
-
return done(err);
|
|
289
|
-
}
|
|
290
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { INotificationRecipient } from './notifications';
|
|
2
|
-
|
|
3
|
-
export interface IRecipient extends INotificationRecipient {
|
|
4
|
-
emailAddress: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface IEmailNotificationType {
|
|
8
|
-
filename: string;
|
|
9
|
-
notifyDoer: boolean;
|
|
10
|
-
notifyOthers: boolean;
|
|
11
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { FormatType, INotificationRecipient } from './notifications';
|
|
2
|
-
// import type { INotificationData } from 'src/lib/model/notification';
|
|
3
|
-
type INotificationData = any;
|
|
4
|
-
export interface IPushNotificationType {
|
|
5
|
-
filename?: string | string[];
|
|
6
|
-
dataOnly?: boolean;
|
|
7
|
-
broadcastToActiveUsers?: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface IPushNotificationService {
|
|
11
|
-
templatePath: string;
|
|
12
|
-
defaultLanguage: string;
|
|
13
|
-
defaultUnit: string;
|
|
14
|
-
subjectPrefix: string;
|
|
15
|
-
pushServerUrl: string;
|
|
16
|
-
pushServerUrlBraze: string;
|
|
17
|
-
availableLanguages: string[];
|
|
18
|
-
authorizationKey: string;
|
|
19
|
-
authorizationKeyBraze: string;
|
|
20
|
-
messageBroker: any;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface IRecipient extends INotificationRecipient {
|
|
24
|
-
walletId: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface ITemplate {
|
|
28
|
-
subject: string;
|
|
29
|
-
body: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface IContents {
|
|
33
|
-
[language: string]: {
|
|
34
|
-
[key in FormatType]?: ITemplate;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface INotifTemplateData extends INotificationData {
|
|
39
|
-
subjectPrefix?: string;
|
|
40
|
-
networkStr?: string;
|
|
41
|
-
rejectorsNames?: string;
|
|
42
|
-
walletId?: string;
|
|
43
|
-
walletName?: string;
|
|
44
|
-
walletM?: number;
|
|
45
|
-
walletN?: number;
|
|
46
|
-
copayerId?: string;
|
|
47
|
-
copayerName?: string;
|
|
48
|
-
rejectedBy?: string[];
|
|
49
|
-
rejectorNames?: string;
|
|
50
|
-
address?: string | { coin: string };
|
|
51
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"delme.d.ts","sourceRoot":"","sources":["../../scripts/delme.ts"],"names":[],"mappings":""}
|