cryptoseed 1.0.0
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/LICENSE +21 -0
- package/README.en.md +224 -0
- package/README.es.md +224 -0
- package/README.fr.md +224 -0
- package/README.he.md +224 -0
- package/README.it.md +224 -0
- package/README.ja.md +224 -0
- package/README.ko.md +224 -0
- package/README.md +224 -0
- package/README.ru.md +224 -0
- package/README.tr.md +224 -0
- package/README.zh.md +224 -0
- package/package.json +61 -0
- package/src/bin/cli.js +1785 -0
- package/src/index.js +27 -0
- package/src/lib/address-deriver.js +1282 -0
- package/src/lib/balance-checker.js +230 -0
- package/src/lib/cli-locales.js +1120 -0
- package/src/lib/electrum-legacy.js +176 -0
- package/src/lib/search-engine.js +576 -0
- package/src/lib/search-worker.js +68 -0
- package/src/lib/typo.js +187 -0
- package/src/lib/wordlists.js +1655 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CryptoSeedRecovery - Balance Checker Subsystem
|
|
3
|
+
* Supports resilient balance lookup for 25+ blockchains.
|
|
4
|
+
* Integrates with standard JSON-RPC (EVM, Solana, XRP) and reliable public API endpoints.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { ethers } = require('ethers');
|
|
8
|
+
|
|
9
|
+
const EVM_NETWORKS = [
|
|
10
|
+
{ name: 'Ethereum Mainnet', id: 'ETH', chainId: 1, rpc: 'https://cloudflare-eth.com', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
11
|
+
{ name: 'BNB Smart Chain', id: 'BSC', chainId: 56, rpc: 'https://bsc-dataseed.binance.org', localRpc: 'http://localhost:8545', symbol: 'BNB' },
|
|
12
|
+
{ name: 'Polygon Mainnet', id: 'POLYGON', chainId: 137, rpc: 'https://polygon-rpc.com', localRpc: 'http://localhost:8545', symbol: 'POL' },
|
|
13
|
+
{ name: 'Arbitrum One', id: 'ARBITRUM', chainId: 42161, rpc: 'https://arb1.arbitrum.io/rpc', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
14
|
+
{ name: 'Optimism Mainnet', id: 'OPTIMISM', chainId: 10, rpc: 'https://mainnet.optimism.io', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
15
|
+
{ name: 'Base Mainnet', id: 'BASE', chainId: 8453, rpc: 'https://mainnet.base.org', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
16
|
+
{ name: 'Avalanche C-Chain', id: 'AVAX', chainId: 43114, rpc: 'https://api.avax.network/ext/bc/C/rpc', localRpc: 'http://localhost:8545', symbol: 'AVAX' },
|
|
17
|
+
{ name: 'Gnosis Chain', id: 'GNOSIS', chainId: 100, rpc: 'https://rpc.gnosischain.com', localRpc: 'http://localhost:8545', symbol: 'xDAI' },
|
|
18
|
+
{ name: 'Sonic Mainnet', id: 'SONIC', chainId: 146, rpc: 'https://rpc.soniclabs.com', localRpc: 'http://localhost:8545', symbol: 'S' },
|
|
19
|
+
{ name: 'Cronos Mainnet', id: 'CRONOS', chainId: 25, rpc: 'https://evm.cronos.org', localRpc: 'http://localhost:8545', symbol: 'CRO' },
|
|
20
|
+
{ name: 'Mantle Mainnet', id: 'MANTLE', chainId: 5000, rpc: 'https://rpc.mantle.xyz', localRpc: 'http://localhost:8545', symbol: 'MNT' },
|
|
21
|
+
{ name: 'Celo Mainnet', id: 'CELO', chainId: 42220, rpc: 'https://forno.celo.org', localRpc: 'http://localhost:8545', symbol: 'CELO' },
|
|
22
|
+
{ name: 'Kava EVM', id: 'KAVA', chainId: 2222, rpc: 'https://evm.kava.io', localRpc: 'http://localhost:8545', symbol: 'KAVA' },
|
|
23
|
+
{ name: 'Moonbeam', id: 'MOONBEAM', chainId: 1284, rpc: 'https://rpc.api.moonbeam.network', localRpc: 'http://localhost:8545', symbol: 'GLMR' },
|
|
24
|
+
{ name: 'Moonriver', id: 'MOONRIVER', chainId: 1285, rpc: 'https://rpc.api.moonriver.moonbeam.network', localRpc: 'http://localhost:8545', symbol: 'MOVR' },
|
|
25
|
+
{ name: 'Rootstock', id: 'ROOTSTOCK', chainId: 30, rpc: 'https://public-node.rsk.co', localRpc: 'http://localhost:8545', symbol: 'RBTC' },
|
|
26
|
+
{ name: 'CoreDAO', id: 'COREDAO', chainId: 1116, rpc: 'https://rpc.coredao.org', localRpc: 'http://localhost:8545', symbol: 'CORE' },
|
|
27
|
+
{ name: 'Linea', id: 'LINEA', chainId: 59144, rpc: 'https://rpc.linea.build', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
28
|
+
{ name: 'Scroll', id: 'SCROLL', chainId: 534352, rpc: 'https://rpc.scroll.io', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
29
|
+
{ name: 'Blast', id: 'BLAST', chainId: 81457, rpc: 'https://rpc.blast.io', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
30
|
+
{ name: 'Mode', id: 'MODE', chainId: 34443, rpc: 'https://mainnet.mode.network', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
31
|
+
{ name: 'Polygon zkEVM', id: 'POLYGON_ZKEVM', chainId: 1101, rpc: 'https://zkevm-rpc.polygon.technology', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
32
|
+
{ name: 'Taiko Mainnet', id: 'TAIKO', chainId: 167000, rpc: 'https://rpc.mainnet.taiko.xyz', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
33
|
+
{ name: 'zkSync Era', id: 'ZKSYNC_ERA', chainId: 324, rpc: 'https://mainnet.era.zksync.io', localRpc: 'http://localhost:8545', symbol: 'ETH' },
|
|
34
|
+
{ name: 'Berachain Mainnet', id: 'BERACHAIN', chainId: 80094, rpc: 'https://rpc.berachain.com', localRpc: 'http://localhost:8545', symbol: 'BERA' },
|
|
35
|
+
{ name: 'Metis Andromeda', id: 'METIS', chainId: 1088, rpc: 'https://andromeda.metis.io/?owner=1088', localRpc: 'http://localhost:8545', symbol: 'METIS' },
|
|
36
|
+
{ name: 'Boba Network', id: 'BOBA', chainId: 288, rpc: 'https://mainnet.boba.network', localRpc: 'http://localhost:8545', symbol: 'ETH' }
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const NON_EVM_DEFAULTS = {
|
|
40
|
+
BTC: { name: 'Bitcoin', rpc: 'https://blockstream.info/api', localRpc: 'http://localhost:8332', symbol: 'BTC' },
|
|
41
|
+
LTC: { name: 'Litecoin', rpc: 'https://litecoinspace.org/api', localRpc: 'http://localhost:9332', symbol: 'LTC' },
|
|
42
|
+
DOGE: { name: 'Dogecoin', rpc: 'https://dogechain.info/api/v1', localRpc: 'http://localhost:22555', symbol: 'DOGE' },
|
|
43
|
+
SOL: { name: 'Solana', rpc: 'https://api.mainnet-beta.solana.com', localRpc: 'http://localhost:8899', symbol: 'SOL' },
|
|
44
|
+
XRP: { name: 'Ripple', rpc: 'https://xrplcluster.com', localRpc: 'http://localhost:5005', symbol: 'XRP' },
|
|
45
|
+
ADA: { name: 'Cardano', rpc: 'https://cardano-mainnet.blockfrost.io/api/v0', localRpc: 'http://localhost:8090', symbol: 'ADA' },
|
|
46
|
+
DOT: { name: 'Polkadot', rpc: 'https://rpc.polkadot.io', localRpc: 'http://localhost:9933', symbol: 'DOT' },
|
|
47
|
+
ATOM: { name: 'Cosmos', rpc: 'https://cosmos-rpc.publicnode.com', localRpc: 'http://localhost:26657', symbol: 'ATOM' },
|
|
48
|
+
TRX: { name: 'Tron', rpc: 'https://api.trongrid.io', localRpc: 'http://localhost:8090', symbol: 'TRX' }
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Resiliently fetches balance of an address on a given blockchain network.
|
|
53
|
+
* Throws clean errors for rate limits (Too Many Requests / 429) or connection issues.
|
|
54
|
+
*/
|
|
55
|
+
async function getBalance(address, coin, rpcUrl) {
|
|
56
|
+
const cleanCoin = coin.toUpperCase().trim();
|
|
57
|
+
const url = rpcUrl.trim();
|
|
58
|
+
|
|
59
|
+
// Helper to run fetch with a short timeout
|
|
60
|
+
const fetchWithTimeout = async (targetUrl, options = {}) => {
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
const id = setTimeout(() => controller.abort(), 6000);
|
|
63
|
+
try {
|
|
64
|
+
const res = await fetch(targetUrl, { ...options, signal: controller.signal });
|
|
65
|
+
clearTimeout(id);
|
|
66
|
+
if (res.status === 429) {
|
|
67
|
+
throw new Error('RATE_LIMIT');
|
|
68
|
+
}
|
|
69
|
+
return res;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
clearTimeout(id);
|
|
72
|
+
if (err.name === 'AbortError') {
|
|
73
|
+
throw new Error('TIMEOUT');
|
|
74
|
+
}
|
|
75
|
+
if (err.message === 'RATE_LIMIT') {
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
throw new Error(`CONNECTION_FAILED: ${err.message}`);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// 1. EVM Balances (ETH, BSC, Polygon, etc.)
|
|
83
|
+
const isEvmCoin = cleanCoin === 'ETH' || cleanCoin === 'EVM' || cleanCoin === 'GNOSIS' || EVM_NETWORKS.some(n => n.id === cleanCoin);
|
|
84
|
+
|
|
85
|
+
if (isEvmCoin) {
|
|
86
|
+
try {
|
|
87
|
+
const provider = new ethers.JsonRpcProvider(url, null, {
|
|
88
|
+
staticNetwork: true
|
|
89
|
+
});
|
|
90
|
+
const balance = await Promise.race([
|
|
91
|
+
provider.getBalance(address),
|
|
92
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('TIMEOUT')), 5000))
|
|
93
|
+
]);
|
|
94
|
+
const formatted = ethers.formatEther(balance);
|
|
95
|
+
const matched = EVM_NETWORKS.find(n => n.id === cleanCoin);
|
|
96
|
+
const symbol = matched ? matched.symbol : 'ETH';
|
|
97
|
+
return `${parseFloat(formatted).toFixed(6)} ${symbol}`;
|
|
98
|
+
} catch (err) {
|
|
99
|
+
if (err.message === 'TIMEOUT') {
|
|
100
|
+
throw new Error('TIMEOUT');
|
|
101
|
+
}
|
|
102
|
+
const errStr = err.message ? err.message.toLowerCase() : '';
|
|
103
|
+
if (errStr.includes('429') || errStr.includes('limit') || errStr.includes('rate') || errStr.includes('too many') || errStr.includes('throttle')) {
|
|
104
|
+
throw new Error('RATE_LIMIT');
|
|
105
|
+
}
|
|
106
|
+
throw new Error(`EVM_QUERY_FAILED: ${err.message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 2. Non-EVM Balances
|
|
111
|
+
try {
|
|
112
|
+
switch (cleanCoin) {
|
|
113
|
+
case 'BTC':
|
|
114
|
+
case 'BITCOIN': {
|
|
115
|
+
if (url.includes('blockstream.info')) {
|
|
116
|
+
const res = await fetchWithTimeout(`${url}/address/${address}`);
|
|
117
|
+
const data = await res.json();
|
|
118
|
+
if (data && data.chain_stats) {
|
|
119
|
+
const satoshis = data.chain_stats.funded_txo_sum - data.chain_stats.spent_txo_sum;
|
|
120
|
+
const btc = satoshis / 1e8;
|
|
121
|
+
return `${btc.toFixed(8)} BTC`;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Fallback or local RPC
|
|
125
|
+
const res = await fetchWithTimeout(url, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers: { 'Content-Type': 'application/json' },
|
|
128
|
+
body: JSON.stringify({
|
|
129
|
+
jsonrpc: '1.0',
|
|
130
|
+
id: 'cryptoseed',
|
|
131
|
+
method: 'getreceivedbyaddress',
|
|
132
|
+
params: [address, 0]
|
|
133
|
+
})
|
|
134
|
+
});
|
|
135
|
+
const data = await res.json();
|
|
136
|
+
if (data && data.result !== undefined) {
|
|
137
|
+
return `${parseFloat(data.result).toFixed(8)} BTC`;
|
|
138
|
+
}
|
|
139
|
+
throw new Error('Invalid response from BTC node');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case 'LTC':
|
|
143
|
+
case 'LITECOIN': {
|
|
144
|
+
if (url.includes('litecoinspace.org')) {
|
|
145
|
+
const res = await fetchWithTimeout(`${url}/address/${address}`);
|
|
146
|
+
const data = await res.json();
|
|
147
|
+
if (data && data.chain_stats) {
|
|
148
|
+
const satoshis = data.chain_stats.funded_txo_sum - data.chain_stats.spent_txo_sum;
|
|
149
|
+
const ltc = satoshis / 1e8;
|
|
150
|
+
return `${ltc.toFixed(8)} LTC`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Local RPC
|
|
154
|
+
const res = await fetchWithTimeout(url, {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
headers: { 'Content-Type': 'application/json' },
|
|
157
|
+
body: JSON.stringify({
|
|
158
|
+
jsonrpc: '1.0',
|
|
159
|
+
id: 'cryptoseed',
|
|
160
|
+
method: 'getreceivedbyaddress',
|
|
161
|
+
params: [address, 0]
|
|
162
|
+
})
|
|
163
|
+
});
|
|
164
|
+
const data = await res.json();
|
|
165
|
+
if (data && data.result !== undefined) {
|
|
166
|
+
return `${parseFloat(data.result).toFixed(8)} LTC`;
|
|
167
|
+
}
|
|
168
|
+
throw new Error('Invalid response from LTC node');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
case 'SOL':
|
|
172
|
+
case 'SOLANA': {
|
|
173
|
+
const res = await fetchWithTimeout(url, {
|
|
174
|
+
method: 'POST',
|
|
175
|
+
headers: { 'Content-Type': 'application/json' },
|
|
176
|
+
body: JSON.stringify({
|
|
177
|
+
jsonrpc: '2.0',
|
|
178
|
+
id: 1,
|
|
179
|
+
method: 'getBalance',
|
|
180
|
+
params: [address]
|
|
181
|
+
})
|
|
182
|
+
});
|
|
183
|
+
const data = await res.json();
|
|
184
|
+
if (data && data.result && data.result.value !== undefined) {
|
|
185
|
+
const sol = data.result.value / 1e9;
|
|
186
|
+
return `${sol.toFixed(6)} SOL`;
|
|
187
|
+
}
|
|
188
|
+
throw new Error('Invalid response from SOL node');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
case 'XRP':
|
|
192
|
+
case 'RIPPLE': {
|
|
193
|
+
const res = await fetchWithTimeout(url, {
|
|
194
|
+
method: 'POST',
|
|
195
|
+
headers: { 'Content-Type': 'application/json' },
|
|
196
|
+
body: JSON.stringify({
|
|
197
|
+
method: 'account_info',
|
|
198
|
+
params: [{ account: address, ledger_index: 'validated' }]
|
|
199
|
+
})
|
|
200
|
+
});
|
|
201
|
+
const data = await res.json();
|
|
202
|
+
if (data && data.result && data.result.account_data) {
|
|
203
|
+
const drops = parseInt(data.result.account_data.Balance || '0', 10);
|
|
204
|
+
const xrp = drops / 1e6;
|
|
205
|
+
return `${xrp.toFixed(6)} XRP`;
|
|
206
|
+
}
|
|
207
|
+
// Account may not be activated on-chain
|
|
208
|
+
if (data && data.result && data.result.error === 'actNotFound') {
|
|
209
|
+
return '0.000000 XRP (Inactive Account)';
|
|
210
|
+
}
|
|
211
|
+
throw new Error('Invalid response from XRP node');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
default:
|
|
215
|
+
// Stubs for other networks or basic mock balance
|
|
216
|
+
return '0.000000 ' + cleanCoin;
|
|
217
|
+
}
|
|
218
|
+
} catch (err) {
|
|
219
|
+
if (err.message === 'RATE_LIMIT' || err.message === 'TIMEOUT') {
|
|
220
|
+
throw err;
|
|
221
|
+
}
|
|
222
|
+
throw new Error(`QUERY_FAILED: ${err.message}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = {
|
|
227
|
+
EVM_NETWORKS,
|
|
228
|
+
NON_EVM_DEFAULTS,
|
|
229
|
+
getBalance
|
|
230
|
+
};
|