-
Notifications
You must be signed in to change notification settings - Fork 3
/
selfSolTransfer.mjs
157 lines (129 loc) · 4.64 KB
/
selfSolTransfer.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// This script does self sol transfer
// node selfSolTransfer.mjs
// Read this to optimize your transactions
// https://docs.triton.one/chains/solana/sending-txs
import {
ComputeBudgetProgram,
Connection,
Keypair,
SystemProgram,
TransactionMessage,
VersionedTransaction,
} from "@solana/web3.js";
import dotenv from "dotenv";
import bs58 from "bs58";
dotenv.config();
const RPC_ENDPOINT =
process.env.RPC_ENDPOINT || "https://api.mainnet-beta.solana.com";
const USER_KEYPAIR = Keypair.fromSecretKey(
bs58.decode(process.env.WALLET_PRIVATE_KEY)
);
const CU_BUDGET = 500;
const PRIORITY_FEE_LAMPORTS = 1;
const TX_RETRY_INTERVAL = 2000;
const connection = new Connection(RPC_ENDPOINT);
async function main() {
let blockhashResult = await connection.getLatestBlockhash({
commitment: "confirmed",
});
// V0 transaction message
const messagev0 = new TransactionMessage({
payerKey: USER_KEYPAIR.publicKey,
recentBlockhash: blockhashResult.blockhash,
instructions: [
// Setting Compute Units Budget
ComputeBudgetProgram.setComputeUnitLimit({
units: CU_BUDGET,
}),
// Setting Priority Fees
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 1_000_000 * PRIORITY_FEE_LAMPORTS,
}),
// Instruction for SOL transfer
SystemProgram.transfer({
fromPubkey: USER_KEYPAIR.publicKey,
toPubkey: USER_KEYPAIR.publicKey,
lamports: 5000,
}),
],
}).compileToV0Message();
// V0 transaction
const tx = new VersionedTransaction(messagev0);
tx.sign([USER_KEYPAIR]);
// Simulating the transaction
const simulationResult = await connection.simulateTransaction(tx, {
commitment: "confirmed",
});
if (simulationResult.value.err) {
throw new Error(
`Transaction simulation failed with error ${JSON.stringify(
simulationResult.value.err
)}`
);
}
console.log(`${new Date().toISOString()} Transaction simulation successful result:`);
console.log(simulationResult);
let txSignature = null;
let confirmTransactionPromise = null;
let confirmedTx = null;
const signatureRaw = tx.signatures[0];
txSignature = bs58.encode(signatureRaw);
let txSendAttempts = 1;
// In the following section, we wait and constantly check for the transaction to be confirmed
// and resend the transaction if it is not confirmed within a certain time interval
// thus handling tx retries on the client side rather than relying on the RPC
try {
// Send and wait confirmation (subscribe on confirmation before sending)
console.log(`${new Date().toISOString()} Subscribing to transaction confirmation`);
// confirmTransaction throws error, handle it
confirmTransactionPromise = connection.confirmTransaction(
{
signature: txSignature,
blockhash: blockhashResult.blockhash,
lastValidBlockHeight: blockhashResult.lastValidBlockHeight,
},
"confirmed"
);
console.log(`${new Date().toISOString()} Sending Transaction ${txSignature}`);
await connection.sendRawTransaction(tx.serialize(), {
// Skipping preflight i.e. tx simulation by RPC as we simulated the tx above
// This allows Triton RPCs to send the transaction through multiple pathways for the fastest delivery
skipPreflight: true,
// Setting max retries to 0 as we are handling retries manually
// Set this manually so that the default is skipped
maxRetries: 0,
});
confirmedTx = null;
while (!confirmedTx) {
confirmedTx = await Promise.race([
confirmTransactionPromise,
new Promise((resolve) =>
setTimeout(() => {
resolve(null);
}, TX_RETRY_INTERVAL)
),
]);
if (confirmedTx) {
break;
}
console.log(`${new Date().toISOString()} Tx not confirmed after ${TX_RETRY_INTERVAL * txSendAttempts++}ms, resending`);
await connection.sendRawTransaction(tx.serialize(), {
// Skipping preflight i.e. tx simulation by RPC as we simulated the tx above
// This allows Triton RPCs to send the transaction through multiple pathways for the fastest delivery
skipPreflight: true,
// Setting max retries to 0 as we are handling retries manually
// Set this manually so that the default is skipped
maxRetries: 0,
});
}
} catch (error) {
console.error(error);
}
if (!confirmedTx) {
console.log(`${new Date().toISOString()} Transaction failed`);
return;
}
console.log(`${new Date().toISOString()} Transaction successful`);
console.log(`${new Date().toISOString()} Explorer URL: https://explorer.solana.com/tx/${txSignature}`);
}
main();