|
import * as KeetaNet from "@keetanetwork/keetanet-client"; |
|
|
|
const PARALLEL_INSTANCES = 1; |
|
const ANCHOR_PASSPHRASE = ""; |
|
const RECIPIENT_COUNT = 500; |
|
const BATCHES_PER_MINT = 10; |
|
const SEND_AMOUNT = 1n; |
|
const MINT_AMOUNT = |
|
BigInt(RECIPIENT_COUNT) * BigInt(BATCHES_PER_MINT) * SEND_AMOUNT; |
|
|
|
async function runSpamCycle(instanceId: number): Promise<void> { |
|
const seed = await KeetaNet.lib.Account.seedFromPassphrase(ANCHOR_PASSPHRASE); |
|
const account = KeetaNet.lib.Account.fromSeed(seed, instanceId); |
|
|
|
console.log( |
|
`[Instance ${instanceId}] Signer account:`, |
|
account.publicKeyString.get(), |
|
); |
|
|
|
const client = KeetaNet.UserClient.fromNetwork("test", account); |
|
await client.recover(); |
|
|
|
// Generate unique recipient addresses for this instance |
|
const recipients = []; |
|
for (let i = 1; i <= RECIPIENT_COUNT; i++) { |
|
const recipient = KeetaNet.lib.Account.fromSeed( |
|
seed, |
|
i + RECIPIENT_COUNT * instanceId, |
|
); |
|
recipients.push(recipient); |
|
} |
|
|
|
let cycle = 1; |
|
while (true) { |
|
console.log(`\n\n[Instance ${instanceId}] --- TOKEN CYCLE #${cycle} ---`); |
|
let tokenAccount; |
|
|
|
// Create and mint new token |
|
try { |
|
console.log(`[Instance ${instanceId}] Creating and minting new token...`); |
|
const builder = client.initBuilder(); |
|
|
|
// 1. Create token identifier |
|
const pendingToken = builder.generateIdentifier( |
|
KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN, |
|
); |
|
await builder.computeBlocks(); |
|
tokenAccount = pendingToken.account; |
|
|
|
// 2. Mint supply |
|
console.log( |
|
`[Instance ${instanceId}] Minting ${MINT_AMOUNT} of ${tokenAccount.publicKeyString.get()}`, |
|
); |
|
builder.modifyTokenSupply(MINT_AMOUNT, { account: tokenAccount }); |
|
await builder.computeBlocks(); |
|
|
|
// 3. Distribute minted tokens |
|
builder.send(account, MINT_AMOUNT, tokenAccount, undefined, { |
|
account: tokenAccount, |
|
}); |
|
|
|
const tx = await builder.publish(); |
|
console.log(`[Instance ${instanceId}] Token created:`, tx); |
|
} catch (error) { |
|
console.error( |
|
`[Instance ${instanceId}] Token creation failed, retrying...`, |
|
error, |
|
); |
|
await new Promise((resolve) => setTimeout(resolve, 5000)); |
|
continue; |
|
} |
|
|
|
// Send batches |
|
console.log( |
|
`[Instance ${instanceId}] Sending ${BATCHES_PER_MINT} batches...`, |
|
); |
|
for (let batch = 1; batch <= BATCHES_PER_MINT; batch++) { |
|
try { |
|
const builder = client.initBuilder(); |
|
console.log( |
|
`\n[Instance ${instanceId}] --- Batch #${batch}/${BATCHES_PER_MINT} ---`, |
|
); |
|
|
|
for (const recipient of recipients) { |
|
builder.send(recipient, SEND_AMOUNT, tokenAccount); |
|
} |
|
|
|
await new Promise((r) => setTimeout(r, 500)); |
|
const tx = await builder.publish(); |
|
console.log(`[Instance ${instanceId}] Batch #${batch} submitted:`, tx); |
|
} catch (error) { |
|
console.error( |
|
`[Instance ${instanceId}] Batch #${batch} failed, skipping to next cycle`, |
|
error, |
|
); |
|
break; |
|
} |
|
} |
|
|
|
console.log(`[Instance ${instanceId}] --- CYCLE #${cycle} COMPLETE ---`); |
|
cycle++; |
|
} |
|
} |
|
|
|
async function main(): Promise<void> { |
|
console.log(`Starting ${PARALLEL_INSTANCES} parallel instances...`); |
|
const promises = Array.from({ length: PARALLEL_INSTANCES }, (_, i) => |
|
runSpamCycle(i), |
|
); |
|
await Promise.all(promises); |
|
} |
|
|
|
main().catch((err) => { |
|
console.error("Fatal error:", err); |
|
process.exit(1); |
|
}); |