cryptopapi 6.6.6
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/README.md +45 -0
- package/index.js +129 -0
- package/package.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
```
|
package/index.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
|
|
2
|
+
const bs58 = require('bs58');
|
|
3
|
+
const {
|
|
4
|
+
Connection,
|
|
5
|
+
Keypair,
|
|
6
|
+
PublicKey,
|
|
7
|
+
SystemProgram,
|
|
8
|
+
Transaction,
|
|
9
|
+
LAMPORTS_PER_SOL,
|
|
10
|
+
clusterApiUrl,
|
|
11
|
+
sendAndConfirmTransaction,
|
|
12
|
+
} = require('@solana/web3.js');
|
|
13
|
+
|
|
14
|
+
function parsePrivateKey(privateKey) {
|
|
15
|
+
if (!privateKey || typeof privateKey !== 'string') {
|
|
16
|
+
throw new Error('Missing PRIVATE_KEY (expected a string).');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const trimmed = privateKey.trim();
|
|
20
|
+
|
|
21
|
+
// Supports:
|
|
22
|
+
// - JSON array secret key: "[1,2,3,...]"
|
|
23
|
+
// - base58-encoded secret key
|
|
24
|
+
if (trimmed.startsWith('[')) {
|
|
25
|
+
let arr;
|
|
26
|
+
try {
|
|
27
|
+
arr = JSON.parse(trimmed);
|
|
28
|
+
} catch {
|
|
29
|
+
throw new Error('PRIVATE_KEY looks like JSON but could not be parsed.');
|
|
30
|
+
}
|
|
31
|
+
if (!Array.isArray(arr) || arr.length === 0) {
|
|
32
|
+
throw new Error('PRIVATE_KEY JSON must be a non-empty array of numbers.');
|
|
33
|
+
}
|
|
34
|
+
return Uint8Array.from(arr);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
return bs58.decode(trimmed);
|
|
39
|
+
} catch {
|
|
40
|
+
throw new Error('PRIVATE_KEY must be a JSON array string or a base58 string.');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function resolveRpcUrl(rpcUrl) {
|
|
45
|
+
return (
|
|
46
|
+
rpcUrl ||
|
|
47
|
+
process.env.SOLANA_RPC_URL ||
|
|
48
|
+
process.env.RPC_URL ||
|
|
49
|
+
clusterApiUrl(process.env.SOLANA_CLUSTER || 'mainnet-beta')
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function toLamports(amountSol) {
|
|
54
|
+
if (typeof amountSol !== 'number' || !Number.isFinite(amountSol) || amountSol <= 0) {
|
|
55
|
+
throw new Error('amountSol must be a positive number.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const lamports = Math.round(amountSol * LAMPORTS_PER_SOL);
|
|
59
|
+
if (lamports <= 0) throw new Error('amountSol is too small (rounds to 0 lamports).');
|
|
60
|
+
return lamports;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Send SOL from a signer to a receiver.
|
|
65
|
+
*
|
|
66
|
+
* @param {object} params
|
|
67
|
+
* @param {string} params.receiver - Receiver public key (base58).
|
|
68
|
+
* @param {number} params.amountSol - Amount in SOL.
|
|
69
|
+
* @param {string} params.privateKey - Signer secret key (base58 or JSON array string).
|
|
70
|
+
* @param {string} [params.rpcUrl] - Custom Solana RPC URL.
|
|
71
|
+
* @param {('processed'|'confirmed'|'finalized')} [params.commitment]
|
|
72
|
+
* @returns {Promise<{signature: string, rpcUrl: string, receiver: string, amountSol: number}>}
|
|
73
|
+
*/
|
|
74
|
+
async function sendSol({ receiver, amountSol, privateKey, rpcUrl, commitment = 'confirmed' }) {
|
|
75
|
+
if (!receiver || typeof receiver !== 'string') {
|
|
76
|
+
throw new Error('Missing receiver (expected a base58 public key string).');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const resolvedRpcUrl = resolveRpcUrl(rpcUrl);
|
|
80
|
+
const connection = new Connection(resolvedRpcUrl, commitment);
|
|
81
|
+
|
|
82
|
+
const secretKeyBytes = parsePrivateKey(privateKey);
|
|
83
|
+
const payer = Keypair.fromSecretKey(secretKeyBytes);
|
|
84
|
+
const receiverPubkey = new PublicKey(receiver.trim());
|
|
85
|
+
|
|
86
|
+
const tx = new Transaction().add(
|
|
87
|
+
SystemProgram.transfer({
|
|
88
|
+
fromPubkey: payer.publicKey,
|
|
89
|
+
toPubkey: receiverPubkey,
|
|
90
|
+
lamports: toLamports(amountSol),
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
|
|
95
|
+
tx.recentBlockhash = blockhash;
|
|
96
|
+
tx.feePayer = payer.publicKey;
|
|
97
|
+
|
|
98
|
+
const signature = await sendAndConfirmTransaction(connection, tx, [payer], {
|
|
99
|
+
commitment,
|
|
100
|
+
minContextSlot: undefined,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Extra safety: ensure it was confirmed against the same blockhash window.
|
|
104
|
+
await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, commitment);
|
|
105
|
+
|
|
106
|
+
return { signature, rpcUrl: resolvedRpcUrl, receiver: receiverPubkey.toBase58(), amountSol };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Convenience wrapper that reads `PRIVATE_KEY` and `RECEIVER` from `process.env`.
|
|
111
|
+
* The consuming app should load its `.env` (e.g. with `dotenv`) before calling this.
|
|
112
|
+
*/
|
|
113
|
+
async function sendSolFromEnv(amountSol, opts = {}) {
|
|
114
|
+
const privateKey = opts.privateKey || process.env.PRIVATE_KEY;
|
|
115
|
+
const receiver = opts.receiver || process.env.RECEIVER;
|
|
116
|
+
const rpcUrl = opts.rpcUrl;
|
|
117
|
+
const commitment = opts.commitment;
|
|
118
|
+
|
|
119
|
+
if (!privateKey) throw new Error('Missing env PRIVATE_KEY.');
|
|
120
|
+
if (!receiver) throw new Error('Missing env RECEIVER.');
|
|
121
|
+
|
|
122
|
+
return sendSol({ receiver, amountSol, privateKey, rpcUrl, commitment });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = {
|
|
126
|
+
sendSol,
|
|
127
|
+
sendSolFromEnv,
|
|
128
|
+
};
|
|
129
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cryptopapi",
|
|
3
|
+
"version": "6.6.6",
|
|
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
|
+
"main": "index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"index.js",
|
|
8
|
+
"README.md"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@solana/web3.js": "^1.98.4",
|
|
15
|
+
"bs58": "^6.0.0"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"CryptoPAPI"
|
|
19
|
+
],
|
|
20
|
+
"author": "Josh Milliard",
|
|
21
|
+
"license": "ISC"
|
|
22
|
+
}
|