Skip to content

Instantly share code, notes, and snippets.

@xescure
Created December 30, 2025 21:29
Show Gist options
  • Select an option

  • Save xescure/bcb9798f9ba34029aeb65ee8531aa8f7 to your computer and use it in GitHub Desktop.

Select an option

Save xescure/bcb9798f9ba34029aeb65ee8531aa8f7 to your computer and use it in GitHub Desktop.
import * as KeetaNet from "@keetanetwork/keetanet-client";
/**
* The number of parallel spamming instances to run concurrently.
*/
const PARALLEL_INSTANCES = 1;
/**
* The passphrase for the main account. This will be used to generate the
* account's seed.
*
* DO NOT USE THIS FOR ANY OTHER PURPOSES OTHER THAN DEMONSTRATION.
*/
const ANCHOR_PASSPHRASE = "";
/**
* The number of addresses to generate and send to in each batch.
*/
const RECIPIENT_COUNT = 500;
/**
* The number of batches to send before creating a new token and re-minting.
*/
const BATCHES_PER_MINT = 10;
/**
* The amount of the new token to send to each recipient in each batch.
*/
const SEND_AMOUNT = 1n;
/**
* The total amount to mint for each new token. This is calculated to be
* exactly enough for all the batches.
*/
const MINT_AMOUNT =
BigInt(RECIPIENT_COUNT) * BigInt(BATCHES_PER_MINT) * SEND_AMOUNT;
/**
* A self-contained function that runs one full cycle of creating a token,
* minting it, and then distributing it in batches.
* @param {number} instanceId - A unique identifier for this parallel instance.
*/
async function runSpamCycle(instanceId) {
// --- KeetaNet Client Setup for this instance ---
const anchorSeed =
await KeetaNet.lib.Account.seedFromPassphrase(ANCHOR_PASSPHRASE);
// Each instance gets its own signer account from the seed to avoid conflicts
const signerAccount = KeetaNet.lib.Account.fromSeed(anchorSeed, instanceId);
console.log(
`[Instance ${instanceId}] Signer account:`,
signerAccount.publicKeyString.get(),
);
const client = KeetaNet.UserClient.fromNetwork("test", signerAccount);
// await client.recover(false);
// --- Generate recipient addresses once at the start ---
// This is quick, so doing it in each instance is fine.
const recipient_addresses = [];
for (let i = 1; i <= RECIPIENT_COUNT; i++) {
const recipient = KeetaNet.lib.Account.fromSeed(
anchorSeed,
i + RECIPIENT_COUNT * instanceId,
); // Offset recipients for uniqueness
recipient_addresses.push(recipient);
}
let tokenCreationCycle = 1;
while (true) {
console.log(
`\n\n[Instance ${instanceId}] --- STARTING TOKEN CREATION CYCLE #${tokenCreationCycle} ---`,
);
let tokenAccount;
// --- 1. Create and Mint a New Token ---
try {
console.log(
`[Instance ${instanceId}] Preparing to create and mint a new token...`,
);
let creationBuilder = client.initBuilder();
const pendingTokenAccount = creationBuilder.generateIdentifier(
KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN,
);
await creationBuilder.computeBlocks();
tokenAccount = pendingTokenAccount.account;
console.log(
`[Instance ${instanceId}] Minting ${MINT_AMOUNT} of ${tokenAccount.publicKeyString.get()}`,
);
creationBuilder.modifyTokenSupply(MINT_AMOUNT, { account: tokenAccount });
await creationBuilder.computeBlocks();
creationBuilder.send(
signerAccount,
MINT_AMOUNT,
tokenAccount,
undefined,
{
account: tokenAccount,
},
);
// await client.recover(false);
const creationTx = await creationBuilder.publish();
console.log(
`[Instance ${instanceId}] Token creation successful. Transaction:`,
creationTx,
);
} catch (error) {
console.error(
`[Instance ${instanceId}] Failed to create token in cycle #${tokenCreationCycle}. Retrying...`,
error,
);
await new Promise((resolve) => setTimeout(resolve, 5000));
continue;
}
// --- 2. Inner Loop for Sending Batches ---
console.log(
`[Instance ${instanceId}] Starting to send ${BATCHES_PER_MINT} batches for the new token.`,
);
for (let batchNum = 1; batchNum <= BATCHES_PER_MINT; batchNum++) {
try {
let batchBuilder = client.initBuilder();
console.log(
`\n[Instance ${instanceId}] --- Starting Batch #${batchNum} of ${BATCHES_PER_MINT} ---`,
);
for (const recipient of recipient_addresses) {
batchBuilder.send(recipient, SEND_AMOUNT, tokenAccount);
}
await new Promise((r) => setTimeout(r, 500));
const batchTx = await batchBuilder.publish();
console.log(
`[Instance ${instanceId}] Batch #${batchNum} submitted successfully. Transaction:`,
batchTx,
);
} catch (error) {
console.error(
`[Instance ${instanceId}] An error occurred in batch #${batchNum}. Skipping to next token cycle.`,
error,
);
break;
}
}
console.log(
`[Instance ${instanceId}] --- FINISHED ALL BATCHES FOR TOKEN CYCLE #${tokenCreationCycle} ---`,
);
tokenCreationCycle++;
}
}
async function main() {
console.log(`Starting ${PARALLEL_INSTANCES} parallel spammer instances...`);
const promises = [];
for (let i = 0; i < PARALLEL_INSTANCES; i++) {
// Each instance is an async function call that runs independently
promises.push(runSpamCycle(i));
}
// Promise.all will run all the runSpamCycle functions concurrently.
// If one of them fails with an unhandled error, it will stop the whole script.
await Promise.all(promises);
}
main().catch((err) => {
console.error("A fatal error occurred in the main execution:", err);
process.exit(1);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment