Last active
May 16, 2024 22:54
-
-
Save NotoriousPyro/f316329f4a2d55ae1506d447716c82ce to your computer and use it in GitHub Desktop.
Create nonce accounts on solana example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
Connection, | |
CreateNonceAccountParams, | |
Keypair, | |
NONCE_ACCOUNT_LENGTH, | |
PublicKey, | |
SystemProgram, | |
Transaction, | |
TransactionMessage, | |
VersionedTransaction, | |
WithdrawNonceParams | |
} from "@solana/web3.js"; | |
import config from "../src/lib/Config"; | |
import bs58 from "bs58"; | |
import fs from 'fs'; | |
import yaml from 'yaml'; | |
import { createComputeBudgetInstruction } from "../src/lib/TransactionBuilder"; | |
const connection = new Connection( | |
config.rpc[0].httpEndpoint, | |
{ | |
disableRetryOnRateLimit: config.rpc[0].disableRetryOnRateLimit, | |
commitment: config.rpc[0].commitment, | |
wsEndpoint: config.rpc[0].wsEndpoint, | |
}, | |
); | |
/** | |
* Create 4 nonce accounts and initialise them. | |
*/ | |
const createNonceAccount = async () => { | |
const instruction = new Transaction(); | |
const keypairs: Keypair[] = [] | |
for (let i = 0; i < 4; i++) { | |
keypairs.push(Keypair.generate()); | |
} | |
console.log("Secret keys for nonce accounts: ") | |
for (const keypair of keypairs) { | |
console.log(bs58.encode(keypair.secretKey)) | |
const rent = await connection.getMinimumBalanceForRentExemption(NONCE_ACCOUNT_LENGTH) | |
const nonceparams: CreateNonceAccountParams = { | |
fromPubkey: config.keypair.publicKey, | |
noncePubkey: keypair.publicKey, | |
authorizedPubkey: config.keypair.publicKey, | |
lamports: rent, | |
}; | |
instruction.add( | |
SystemProgram.createNonceAccount(nonceparams), | |
) | |
} | |
const bhInfo = await connection.getLatestBlockhashAndContext({ commitment: "finalized" }); | |
const messageV0 = new TransactionMessage({ | |
payerKey: config.keypair.publicKey, | |
recentBlockhash: bhInfo.value.blockhash, | |
instructions: [ | |
...createComputeBudgetInstruction( | |
100_000, 100 | |
), | |
...instruction.instructions | |
], | |
}).compileToV0Message(); | |
const tx = new VersionedTransaction(messageV0); | |
tx.sign([config.keypair, ...keypairs]); | |
const simulation = await connection.simulateTransaction(tx, { commitment: "confirmed" }); | |
if (simulation.value.err) { | |
throw new Error(`Simulation failed: ${simulation.value.err.toString()}`); | |
} | |
try { | |
const signature = await connection.sendTransaction(tx, { | |
maxRetries: 20, | |
skipPreflight: false, | |
preflightCommitment: "confirmed", | |
}); | |
const confirmation = await connection.confirmTransaction({ | |
signature, | |
blockhash: bhInfo.value.blockhash, | |
lastValidBlockHeight: bhInfo.value.lastValidBlockHeight, | |
}, "confirmed"); | |
if (confirmation.value.err) { | |
throw new Error(`Transaction not confirmed: ${confirmation.value.err.toString()}`); | |
} | |
console.log("Confirmed: ", signature); | |
fs.appendFileSync("noncekeys.yaml", yaml.stringify(keypairs.map(keypair => bs58.encode(keypair.secretKey)))); | |
fs.appendFileSync("noncepubkeys.yaml", yaml.stringify(keypairs.map(keypair => keypair.publicKey.toString()))); | |
} catch (error) { | |
console.error("Failed: ", error); | |
throw error; | |
} | |
} | |
/** | |
* Withdraw the lamports from the nonce accounts and close them. | |
*/ | |
const withdrawNonceAccount = async () => { | |
const publicKeys: PublicKey[] = [ | |
].map(secret => new PublicKey(secret)); | |
console.log("Secret keys for nonce accounts: ") | |
const chunkSize = 5; | |
for (let i = 0; i < publicKeys.length; i += chunkSize) { | |
const instruction = new Transaction(); | |
const chunk = publicKeys.slice(i, i + chunkSize); | |
for (const publicKey of chunk) { | |
const rent = await connection.getMinimumBalanceForRentExemption(NONCE_ACCOUNT_LENGTH) | |
const nonceparams: WithdrawNonceParams = { | |
noncePubkey: publicKey, | |
authorizedPubkey: config.keypair.publicKey, | |
toPubkey: config.keypair.publicKey, | |
lamports: rent, | |
}; | |
instruction.add( | |
SystemProgram.nonceWithdraw(nonceparams), | |
) | |
} | |
// eslint-disable-next-line no-constant-condition | |
while (true) { | |
const bhInfo = await connection.getLatestBlockhashAndContext(); | |
const messageV0 = new TransactionMessage({ | |
payerKey: config.keypair.publicKey, | |
recentBlockhash: bhInfo.value.blockhash, | |
instructions: [ | |
...createComputeBudgetInstruction( | |
100_000, 100 | |
), | |
...instruction.instructions | |
], | |
}).compileToV0Message(); | |
const tx = new VersionedTransaction(messageV0); | |
tx.sign([config.keypair]); | |
const simulation = await connection.simulateTransaction(tx, { commitment: "confirmed" }); | |
console.log("Simulation: ", simulation.value); | |
if (simulation.value.err === "BlockhashNotFound") { | |
continue; | |
} | |
try { | |
const signature = await connection.sendTransaction(tx, { | |
maxRetries: 20, | |
skipPreflight: false, | |
}); | |
const confirmation = await connection.confirmTransaction({ | |
signature, | |
blockhash: bhInfo.value.blockhash, | |
lastValidBlockHeight: bhInfo.value.lastValidBlockHeight, | |
}, "confirmed"); | |
if (confirmation.value.err) { | |
throw new Error(`Transaction not confirmed: ${confirmation.value.err.toString()}`); | |
} | |
console.log("Confirmed: ", signature); | |
} catch (error) { | |
console.error("Failed: ", error); | |
throw error; | |
} | |
break; | |
} | |
} | |
} | |
// uncomment what you want to do | |
createNonceAccount(); | |
//withdrawNonceAccount(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment