@cryptforge/blockchain-evm 0.1.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.
@@ -0,0 +1,580 @@
1
+ import { TokenBalance, TransactionOptions, Transaction, TokenTransfer, BlockchainAdapter, ChainData, KeyData } from '@cryptforge/core';
2
+ export { TokenBalance, TokenTransfer, Transaction, TransactionOptions } from '@cryptforge/core';
3
+
4
+ /**
5
+ * Interface for blockchain data providers (indexers/explorers).
6
+ * Implementations fetch wallet data from various sources (Alchemy, Etherscan, etc.)
7
+ */
8
+ interface BlockchainDataProvider {
9
+ /**
10
+ * Get native token balance for an address
11
+ * @param address - Wallet address
12
+ * @returns TokenBalance object with native token information
13
+ */
14
+ getNativeBalance(address: string): Promise<TokenBalance>;
15
+ /**
16
+ * Get all ERC-20 token balances for an address
17
+ * @param address - Wallet address
18
+ * @returns Array of token balances with metadata
19
+ */
20
+ getTokenBalances(address: string): Promise<TokenBalance[]>;
21
+ /**
22
+ * Get balance for a specific ERC-20 token
23
+ * @param address - Wallet address
24
+ * @param tokenAddress - Token contract address
25
+ * @returns Balance in smallest unit as string
26
+ */
27
+ getTokenBalance(address: string, tokenAddress: string): Promise<string>;
28
+ /**
29
+ * Get all transactions for an address
30
+ * @param address - Wallet address
31
+ * @param options - Optional filtering and pagination options
32
+ * @returns Array of transactions
33
+ */
34
+ getTransactions(address: string, options?: TransactionOptions): Promise<Transaction[]>;
35
+ /**
36
+ * Get all ERC-20 token transfers for an address
37
+ * @param address - Wallet address
38
+ * @param options - Optional filtering and pagination options
39
+ * @returns Array of token transfers
40
+ */
41
+ getTokenTransfers(address: string, options?: TransactionOptions): Promise<TokenTransfer[]>;
42
+ }
43
+
44
+ /**
45
+ * Network configuration for a specific blockchain network (mainnet, testnet, etc.)
46
+ */
47
+ interface NetworkConfig {
48
+ /** Network name (e.g., "Ethereum Mainnet", "Sonic Testnet") */
49
+ name: string;
50
+ /** RPC endpoint URL */
51
+ rpcUrl: string;
52
+ /** Block explorer URL (optional) */
53
+ explorerUrl?: string;
54
+ /** Chain ID for the network */
55
+ chainId: number;
56
+ }
57
+ /**
58
+ * Configuration options for EVM blockchain adapter
59
+ */
60
+ interface EVMAdapterConfig {
61
+ /** Chain metadata (name, symbol, CMC ID) */
62
+ chainData: ChainData;
63
+ /** BIP44 coin type (default: 60 for Ethereum) */
64
+ coinType?: number;
65
+ /** Standard decimals for the chain's native token (default: 18) */
66
+ standardDecimals?: number;
67
+ /** Network configurations (mainnet, testnet, custom networks) */
68
+ networks?: {
69
+ mainnet?: NetworkConfig;
70
+ testnet?: NetworkConfig;
71
+ [key: string]: NetworkConfig | undefined;
72
+ };
73
+ /** Default network to use (default: 'mainnet') */
74
+ defaultNetwork?: string;
75
+ /** Optional data provider for fetching balances and transactions */
76
+ dataProvider?: BlockchainDataProvider;
77
+ /** BIP44 account index (default: 0) */
78
+ account?: number;
79
+ /** BIP44 change index (default: 0) */
80
+ change?: number;
81
+ /** BIP44 address index (default: 0) */
82
+ addressIndex?: number;
83
+ }
84
+ /**
85
+ * Configurable EVM blockchain adapter for CryptForge SDK.
86
+ * Supports all EVM-compatible blockchains (Ethereum, Sonic, Polygon, BSC, etc.)
87
+ * Uses ethers.js for key derivation and wallet operations.
88
+ */
89
+ declare class EVMAdapter implements BlockchainAdapter {
90
+ readonly chainData: ChainData;
91
+ readonly standardDecimals: number;
92
+ private readonly coinType;
93
+ private readonly account;
94
+ private readonly change;
95
+ private readonly addressIndex;
96
+ private readonly networks;
97
+ private currentNetworkKey;
98
+ private dataProvider?;
99
+ /**
100
+ * Create a new EVM blockchain adapter
101
+ * @param config - Chain configuration
102
+ */
103
+ constructor(config: EVMAdapterConfig);
104
+ /**
105
+ * Get the BIP44 derivation path for this chain
106
+ * @returns BIP44 path string (e.g., "m/44'/60'/0'/0/0")
107
+ */
108
+ private getDerivationPath;
109
+ /**
110
+ * Get the current network configuration
111
+ * @returns Current network configuration, or undefined if no network is configured
112
+ */
113
+ getNetwork(): NetworkConfig | undefined;
114
+ /**
115
+ * Get the current network key (e.g., 'mainnet', 'testnet')
116
+ * @returns Current network key
117
+ */
118
+ getCurrentNetworkKey(): string;
119
+ /**
120
+ * Set the active network
121
+ * @param networkKey - Network key to switch to (e.g., 'mainnet', 'testnet')
122
+ * @throws Error if the network key doesn't exist
123
+ */
124
+ setNetwork(networkKey: string): void;
125
+ /**
126
+ * Get all available network keys
127
+ * @returns Array of network keys (e.g., ['mainnet', 'testnet'])
128
+ */
129
+ getAvailableNetworks(): string[];
130
+ /**
131
+ * Check if a network is configured
132
+ * @param networkKey - Network key to check
133
+ * @returns True if the network exists
134
+ */
135
+ hasNetwork(networkKey: string): boolean;
136
+ /**
137
+ * Derive EVM keys from a BIP39 mnemonic.
138
+ * Uses the BIP44 derivation path specified in the configuration.
139
+ *
140
+ * @param mnemonic - BIP39 mnemonic phrase
141
+ * @returns KeyData with derived keys and address
142
+ */
143
+ deriveKeys(mnemonic: string): Promise<KeyData>;
144
+ /**
145
+ * Derive keys at a specific address index
146
+ * @param mnemonic - BIP39 mnemonic phrase
147
+ * @param addressIndex - Address index in the BIP44 path
148
+ * @returns KeyData with derived keys
149
+ */
150
+ deriveKeysAtIndex(mnemonic: string, addressIndex: number): Promise<KeyData>;
151
+ /**
152
+ * Derive keys at a custom derivation path
153
+ * @param mnemonic - BIP39 mnemonic phrase
154
+ * @param path - Full BIP44 derivation path
155
+ * @returns KeyData with derived keys
156
+ */
157
+ deriveKeysAtPath(mnemonic: string, path: string): Promise<KeyData>;
158
+ /**
159
+ * Get address at a specific index (read-only, no private key)
160
+ * @param mnemonic - BIP39 mnemonic phrase
161
+ * @param index - Address index
162
+ * @returns Address and public key information
163
+ */
164
+ getAddressAtIndex(mnemonic: string, index: number): Promise<{
165
+ address: string;
166
+ publicKey: string;
167
+ path: string;
168
+ }>;
169
+ /**
170
+ * Get multiple addresses starting from an index
171
+ * @param mnemonic - BIP39 mnemonic phrase
172
+ * @param startIndex - Starting address index
173
+ * @param count - Number of addresses to generate
174
+ * @returns Array of addresses with metadata
175
+ */
176
+ getAddresses(mnemonic: string, startIndex: number, count: number): Promise<Array<{
177
+ address: string;
178
+ path: string;
179
+ index: number;
180
+ }>>;
181
+ /**
182
+ * Sign a message with a private key
183
+ * @param privateKey - Private key as Uint8Array
184
+ * @param message - Message to sign (string or Uint8Array)
185
+ * @returns Signature
186
+ */
187
+ signMessage(privateKey: Uint8Array, message: string | Uint8Array): Promise<{
188
+ signature: string;
189
+ }>;
190
+ /**
191
+ * Sign a transaction with a private key
192
+ * @param privateKey - Private key as Uint8Array
193
+ * @param transaction - Chain-specific transaction object
194
+ * @returns Signed transaction and signature
195
+ */
196
+ signTransaction(privateKey: Uint8Array, transaction: any): Promise<{
197
+ signedTransaction: any;
198
+ signature: string;
199
+ }>;
200
+ /**
201
+ * Verify a signature against a public key
202
+ * @param message - Original message
203
+ * @param signature - Signature to verify
204
+ * @param publicKey - Public key (hex string)
205
+ * @returns True if signature is valid
206
+ */
207
+ verifySignature(message: string | Uint8Array, signature: string, publicKey: string): Promise<boolean>;
208
+ /**
209
+ * Set or update the data provider
210
+ * @param provider - The blockchain data provider to use
211
+ */
212
+ setDataProvider(provider: BlockchainDataProvider): void;
213
+ /**
214
+ * Get the current data provider
215
+ * @returns The current data provider, or undefined if not set
216
+ */
217
+ getDataProvider(): BlockchainDataProvider | undefined;
218
+ /**
219
+ * Ensure a data provider is configured
220
+ * @throws Error if no data provider is set
221
+ */
222
+ private ensureProvider;
223
+ /**
224
+ * Get native token balance for an address
225
+ * @param address - Wallet address
226
+ * @returns TokenBalance object with native token information
227
+ * @throws Error if no data provider is configured
228
+ */
229
+ getNativeBalance(address: string): Promise<TokenBalance>;
230
+ /**
231
+ * Get all ERC-20 token balances for an address
232
+ * @param address - Wallet address
233
+ * @returns Array of token balances with metadata
234
+ * @throws Error if no data provider is configured
235
+ */
236
+ getTokenBalances(address: string): Promise<TokenBalance[]>;
237
+ /**
238
+ * Get balance for a specific ERC-20 token
239
+ * @param address - Wallet address
240
+ * @param tokenAddress - Token contract address
241
+ * @returns Balance in smallest unit as string
242
+ * @throws Error if no data provider is configured
243
+ */
244
+ getTokenBalance(address: string, tokenAddress: string): Promise<string>;
245
+ /**
246
+ * Get all transactions for an address
247
+ * @param address - Wallet address
248
+ * @param options - Optional filtering and pagination options
249
+ * @returns Array of transactions
250
+ * @throws Error if no data provider is configured
251
+ */
252
+ getTransactions(address: string, options?: TransactionOptions): Promise<Transaction[]>;
253
+ /**
254
+ * Get all ERC-20 token transfers for an address
255
+ * @param address - Wallet address
256
+ * @param options - Optional filtering and pagination options
257
+ * @returns Array of token transfers
258
+ * @throws Error if no data provider is configured
259
+ */
260
+ getTokenTransfers(address: string, options?: TransactionOptions): Promise<TokenTransfer[]>;
261
+ /**
262
+ * Validate if an address is a valid ERC-20 token contract
263
+ * @param tokenAddress - Token contract address
264
+ * @returns True if valid ERC-20, false otherwise
265
+ */
266
+ validateTokenContract(tokenAddress: string): Promise<boolean>;
267
+ /**
268
+ * Send native tokens (ETH, S, etc.)
269
+ * @param params - Transaction parameters including private key
270
+ * @returns Transaction receipt
271
+ */
272
+ sendNativeToken(params: {
273
+ privateKey: Uint8Array;
274
+ to: string;
275
+ amount: string;
276
+ }): Promise<{
277
+ hash: string;
278
+ from: string;
279
+ to: string;
280
+ value: string;
281
+ chainId: number;
282
+ status: "pending";
283
+ nonce: number;
284
+ }>;
285
+ /**
286
+ * Send ERC-20 tokens
287
+ * Private key must be obtained from AuthClient after password verification
288
+ * @param params - Transaction parameters including private key and token address
289
+ * @returns Transaction receipt
290
+ */
291
+ sendToken(params: {
292
+ privateKey: Uint8Array;
293
+ to: string;
294
+ tokenAddress: string;
295
+ amount: string;
296
+ }): Promise<{
297
+ hash: string;
298
+ from: string;
299
+ to: string;
300
+ value: string;
301
+ chainId: number;
302
+ status: "pending";
303
+ nonce: number;
304
+ }>;
305
+ /**
306
+ * Wait for transaction confirmation and return detailed status
307
+ * @param hash - Transaction hash
308
+ * @returns Transaction status update
309
+ */
310
+ getTransactionStatus(hash: string): Promise<{
311
+ hash: string;
312
+ status: "pending" | "confirmed" | "failed";
313
+ blockNumber?: number;
314
+ confirmations?: number;
315
+ error?: string;
316
+ gasUsed?: string;
317
+ }>;
318
+ private bytesToHex;
319
+ private hexToBytes;
320
+ }
321
+
322
+ /**
323
+ * Configuration for Alchemy provider
324
+ */
325
+ interface AlchemyProviderConfig {
326
+ /** Alchemy API key */
327
+ apiKey: string;
328
+ /** Network identifier for Portfolio API (e.g., "sonic-mainnet", "eth-mainnet") */
329
+ network: string;
330
+ /** RPC URL for direct blockchain queries */
331
+ rpcUrl: string;
332
+ /** Native token symbol (e.g., "ETH", "S") */
333
+ nativeTokenSymbol: string;
334
+ /** Native token name (e.g., "Ethereum", "Sonic") */
335
+ nativeTokenName: string;
336
+ /** Native token decimals (default: 18) */
337
+ nativeTokenDecimals?: number;
338
+ /** CoinMarketCap ID for logo URL */
339
+ cmc_id: number;
340
+ }
341
+ /**
342
+ * Blockchain data provider using Alchemy Portfolio API.
343
+ * Fetches wallet balances, transactions, and token data from Alchemy's indexer.
344
+ *
345
+ * Uses Alchemy's Portfolio API for token balances and direct RPC for other queries.
346
+ *
347
+ * @example
348
+ * ```typescript
349
+ * import { AlchemyProvider } from '@cryptforge/blockchain-evm';
350
+ *
351
+ * const provider = new AlchemyProvider({
352
+ * apiKey: process.env.ALCHEMY_API_KEY!,
353
+ * network: "sonic-mainnet",
354
+ * rpcUrl: "https://sonic-mainnet.g.alchemy.com/v2/YOUR_API_KEY",
355
+ * });
356
+ *
357
+ * const balance = await provider.getNativeBalance('0x...');
358
+ * const tokens = await provider.getTokenBalances('0x...');
359
+ * ```
360
+ */
361
+ declare class AlchemyProvider implements BlockchainDataProvider {
362
+ private apiKey;
363
+ private network;
364
+ private provider;
365
+ private nativeTokenSymbol;
366
+ private nativeTokenName;
367
+ private nativeTokenDecimals;
368
+ private cmc_id;
369
+ constructor(config: AlchemyProviderConfig);
370
+ /**
371
+ * Get native token balance (e.g., ETH, S) for an address using RPC
372
+ */
373
+ getNativeBalance(address: string): Promise<TokenBalance>;
374
+ /**
375
+ * Get all ERC-20 token balances for an address using Alchemy Portfolio API
376
+ */
377
+ getTokenBalances(address: string): Promise<TokenBalance[]>;
378
+ /**
379
+ * Get balance for a specific ERC-20 token using RPC
380
+ */
381
+ getTokenBalance(address: string, tokenAddress: string): Promise<string>;
382
+ /**
383
+ * Get all transactions for an address using Alchemy's getAssetTransfers API
384
+ */
385
+ getTransactions(address: string, options?: TransactionOptions): Promise<Transaction[]>;
386
+ /**
387
+ * Get all ERC-20 token transfers for an address using Alchemy's getAssetTransfers API
388
+ */
389
+ getTokenTransfers(address: string, options?: TransactionOptions): Promise<TokenTransfer[]>;
390
+ /**
391
+ * Helper method to fetch asset transfers from Alchemy API
392
+ */
393
+ private fetchAssetTransfers;
394
+ }
395
+
396
+ /**
397
+ * Etherscan provider configuration
398
+ */
399
+ interface EtherscanProviderConfig {
400
+ /** Etherscan API key (works across all supported chains) */
401
+ apiKey: string;
402
+ /** Chain ID (e.g., 1 for Ethereum, 146 for Sonic, 137 for Polygon) */
403
+ chainId: number;
404
+ /** Native token symbol (e.g., "ETH", "S") */
405
+ nativeTokenSymbol: string;
406
+ /** Native token name (e.g., "Ethereum", "Sonic") */
407
+ nativeTokenName: string;
408
+ /** Native token decimals (default: 18) */
409
+ nativeTokenDecimals?: number;
410
+ /** CoinMarketCap ID for logo URL */
411
+ cmc_id: number;
412
+ /** Etherscan API V2 base URL (default: https://api.etherscan.io/v2/api) */
413
+ baseUrl?: string;
414
+ }
415
+ /**
416
+ * Etherscan-based blockchain data provider
417
+ * Uses Etherscan API V2 to fetch wallet data and transaction history
418
+ */
419
+ declare class EtherscanProvider implements BlockchainDataProvider {
420
+ private apiKey;
421
+ private chainId;
422
+ private baseUrl;
423
+ private nativeTokenSymbol;
424
+ private nativeTokenName;
425
+ private nativeTokenDecimals;
426
+ private cmc_id;
427
+ /**
428
+ * Create an Etherscan provider using API V2
429
+ * @param config - Provider configuration
430
+ */
431
+ constructor(config: EtherscanProviderConfig);
432
+ /**
433
+ * Get native token balance for an address
434
+ * @param address - Wallet address
435
+ * @returns TokenBalance object with native token information
436
+ */
437
+ getNativeBalance(address: string): Promise<TokenBalance>;
438
+ /**
439
+ * Get all ERC-20 token balances for an address
440
+ * @param address - Wallet address
441
+ * @returns Array of token balances with metadata
442
+ *
443
+ * Note: This endpoint prefers the Etherscan API Pro endpoint for better performance,
444
+ * but automatically falls back to a free-tier compatible approach if needed.
445
+ */
446
+ getTokenBalances(address: string): Promise<TokenBalance[]>;
447
+ /**
448
+ * Free-tier fallback for getTokenBalances
449
+ * Discovers tokens via transfer history and fetches individual balances
450
+ * Rate-limited to respect Etherscan free tier limits (3 calls/sec)
451
+ * @param address - Wallet address
452
+ * @returns Array of token balances with metadata
453
+ */
454
+ private getTokenBalancesFallback;
455
+ /**
456
+ * Helper method to add delay (for rate limiting)
457
+ * @param ms - Milliseconds to delay
458
+ */
459
+ private delay;
460
+ /**
461
+ * Wrapper for fetch with automatic retry on rate limit
462
+ * @param url - URL to fetch
463
+ * @param maxRetries - Maximum number of retries (default: 2)
464
+ * @returns Response
465
+ */
466
+ private fetchWithRetry;
467
+ /**
468
+ * Get balance for a specific ERC-20 token
469
+ * @param address - Wallet address
470
+ * @param tokenAddress - Token contract address
471
+ * @returns Balance in smallest unit as string
472
+ */
473
+ getTokenBalance(address: string, tokenAddress: string): Promise<string>;
474
+ /**
475
+ * Get all transactions for an address
476
+ * @param address - Wallet address
477
+ * @param options - Optional filtering and pagination options
478
+ * @returns Array of transactions
479
+ */
480
+ getTransactions(address: string, options?: TransactionOptions): Promise<Transaction[]>;
481
+ /**
482
+ * Get all ERC-20 token transfers for an address
483
+ * @param address - Wallet address
484
+ * @param options - Optional filtering and pagination options
485
+ * @returns Array of token transfers
486
+ */
487
+ getTokenTransfers(address: string, options?: TransactionOptions): Promise<TokenTransfer[]>;
488
+ }
489
+
490
+ /**
491
+ * Pre-configured Ethereum adapter.
492
+ * Uses standard Ethereum derivation path: m/44'/60'/0'/0/0
493
+ *
494
+ * Network Configuration:
495
+ * - Mainnet: Ethereum Mainnet (Chain ID: 1)
496
+ * - Testnet: Sepolia (Chain ID: 11155111)
497
+ *
498
+ * Note: RPC URLs use Infura. Replace 'YOUR_INFURA_API_KEY' with your actual API key,
499
+ * or create a custom adapter with your preferred RPC provider.
500
+ *
501
+ * @example
502
+ * ```typescript
503
+ * import { EthereumAdapter } from '@cryptforge/blockchain-evm';
504
+ *
505
+ * // Use pre-configured adapter
506
+ * setupCryptForgeHandlers({
507
+ * blockchainAdapters: {
508
+ * Ethereum: EthereumAdapter,
509
+ * }
510
+ * });
511
+ *
512
+ * // Get network info
513
+ * const network = EthereumAdapter.getNetwork(); // mainnet by default
514
+ * console.log(network?.rpcUrl);
515
+ *
516
+ * // Switch to testnet
517
+ * EthereumAdapter.setNetwork('testnet');
518
+ * ```
519
+ *
520
+ * @example Custom RPC Configuration
521
+ * ```typescript
522
+ * import { EVMAdapter } from '@cryptforge/blockchain-evm';
523
+ *
524
+ * const CustomEthereum = new EVMAdapter({
525
+ * chainData: { name: "Ethereum", symbol: "ETH", cmc_id: 1027 },
526
+ * coinType: 60,
527
+ * standardDecimals: 18,
528
+ * networks: {
529
+ * mainnet: {
530
+ * name: "Ethereum Mainnet",
531
+ * rpcUrl: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`,
532
+ * explorerUrl: "https://etherscan.io",
533
+ * chainId: 1,
534
+ * },
535
+ * testnet: {
536
+ * name: "Ethereum Testnet (Sepolia)",
537
+ * rpcUrl: `https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY}`,
538
+ * explorerUrl: "https://sepolia.etherscan.io",
539
+ * chainId: 11155111,
540
+ * },
541
+ * },
542
+ * });
543
+ * ```
544
+ */
545
+ declare const EthereumAdapter: EVMAdapter;
546
+
547
+ /**
548
+ * Pre-configured Sonic adapter.
549
+ * Sonic is an EVM-compatible Layer 2 blockchain.
550
+ * Uses standard Ethereum derivation path: m/44'/60'/0'/0/0
551
+ *
552
+ * Network Configuration:
553
+ * - Mainnet: Sonic Mainnet (Chain ID: 146)
554
+ * - Testnet: Sonic Testnet (Chain ID: 57054)
555
+ *
556
+ * @example
557
+ * ```typescript
558
+ * import { SonicAdapter } from '@cryptforge/blockchain-evm';
559
+ *
560
+ * // Use pre-configured adapter
561
+ * setupCryptForgeHandlers({
562
+ * blockchainAdapters: {
563
+ * Sonic: SonicAdapter,
564
+ * }
565
+ * });
566
+ *
567
+ * // Get network info
568
+ * const network = SonicAdapter.getNetwork(); // mainnet by default
569
+ * console.log(network?.rpcUrl); // "https://rpc.sonic.soniclabs.com"
570
+ * console.log(network?.chainId); // 146
571
+ *
572
+ * // Switch to testnet
573
+ * SonicAdapter.setNetwork('testnet');
574
+ * const testnetNetwork = SonicAdapter.getNetwork();
575
+ * console.log(testnetNetwork?.chainId); // 57054
576
+ * ```
577
+ */
578
+ declare const SonicAdapter: EVMAdapter;
579
+
580
+ export { AlchemyProvider, type AlchemyProviderConfig, type BlockchainDataProvider, EVMAdapter, type EVMAdapterConfig, EthereumAdapter, EtherscanProvider, type EtherscanProviderConfig, type NetworkConfig, SonicAdapter };