Blog Article

How Recovers From a Testnet Reset


Carl Vitullo

Publishing date


The new has a section on the homepage with runnable code samples demonstrating features of the network. You can create a new account, send a payment, issue an asset, or even create an offer on the decentralized exchange. Some of these, like creating an account, can be done entirely from the browser, but some require certain prerequisites of the testnet.

Our payment destination and buy offer script both require accounts to exist before the script is run. The testnet is reset every 3 months, though (you can find the reset schedule here), and setting up a quarterly reminder to manually create the accounts didn't sound like fun. Instead, we set up a script.

The script itself is quite straightforward. It checks whether a known account exists, and if it doesn't, it submits a handful of transactions.

 .then((res) => {
 // If the account doesn't exist, create it.
 if (res.status === 404) {
 return fetch(`${paymentAddress}`);
 return Promise.reject("Payment account exists");

That's it! Because creating paymentAddress is part of this reset script, we know that if it doesn't exist on the testnet, there must have been a reset. The rest of the script is a little more verbose, but it follows the same pattern: if our known account 404s, submit transactions so the testnet has everything we need.

Be nice to friendbot

One of our concerns when writing these examples was how quickly they had the potential to drain Friendbot's coffers. Most of these scripts fund at least 1 account with 10,000 XLM, and while the testnet isn't limited, it does cause some short-term issues if Friendbot runs out of Lumens. If somebody decided to run the payment example a dozen times, that would be a whole lot of testnet lumens being burned.

To minimize the odds of that happening, we added a small function to automatically merge the accounts we create back into friendbot. Keen eyes will spot several recoupLumens() calls throughout the examples, which has its definition hidden to keep the examples short. That function's definition is below.

const recoupLumens = async (secret) => {
 const StellarSdk = require("stellar-sdk");
 const server = new StellarSdk.Server("");

 const keypair = StellarSdk.Keypair.fromSecret(secret);
 const [{ p90_accepted_fee: fee }, account] = await Promise.all([
 const tx = new StellarSdk.TransactionBuilder(account, {
 networkPassphrase: StellarSdk.Networks.TESTNET
 await server.submitTransaction(tx).catch(() => {});

This lets us freely create accounts without worrying about impacting the testnet. Between this recoup function and our periodically run reset script, we've now weathered 2 testnet resets without any disruption to the example code on the website!