In this tutorial we will be setting up scripts to send and monitor transfers on the Stellar network.
I’ll be using Node.js and the Stellar-SDK library. All the code is open source and you can fork the repository here: https://github.com/jamesbachini/Stellar-Cross-Border-Test
There are two scripts, send.js
and receive.js
, created to programmatically send a transfer of XLM or another digital asset from one account to another. The time is calculated between sending the transaction and notification of receipt from the receiving horizon node.
Let’s start with send.js
Sending Stellar Transactions
This code demonstrates sending a Stellar network payment using the Stellar SDK.
const StellarSdk = require('stellar-sdk');
const init = async () => {
const sourceSecretKey = 'SBSVNW4CEP4SGH6OJ5NE4EQW2AGTVP2BWMWQ76IE77KCIQXIWCG2T5KN';
const sourceKeypair = StellarSdk.Keypair.fromSecret(sourceSecretKey);
const sourcePublicKey = sourceKeypair.publicKey();
const receiverPublicKey = 'GCG4VZZ6ZTYACRSTIHKXYEZENRAUFTKNGLE4XPQVCAZ7O5XM6W6PSVQI';
const server = new StellarSdk.Horizon.Server('https://horizon-testnet.stellar.org');
const networkPassphrase = StellarSdk.Networks.TESTNET;
const account = await server.loadAccount(sourcePublicKey);
const fee = await server.fetchBaseFee();
const sentTimestamp = Date.now();
console.log(`Sending Timestamp: ${sentTimestamp}`);
const transaction = new StellarSdk.TransactionBuilder(account, {
fee,
networkPassphrase
})
.addOperation(StellarSdk.Operation.payment({
destination: receiverPublicKey,
asset: StellarSdk.Asset.native(),
amount: '1',
}))
.setTimeout(30)
.build();
console.log('Sending...')
transaction.sign(sourceKeypair);
try {
const transactionResult = await server.submitTransaction(transaction);
const receivedTimestamp = Date.now();
console.log(`Received Timestamp: ${receivedTimestamp}`);
console.log('Success! View the transaction at: ');
console.log(`https://stellar.expert/explorer/testnet/tx/${transactionResult._links.transaction.href.split('/').at(-1)}`);
const localTimeTaken = receivedTimestamp - sentTimestamp;
console.log(`Local Confirmation Time: ${localTimeTaken}ms (${(localTimeTaken / 1000)} seconds)`);
process.stdout.write('Enter the timestamp for the received transaction: ');
process.stdin.once('data', (data) => {
const externalTimestamp = data.toString().trim();
process.stdin.end();
const timeTaken = externalTimestamp - sentTimestamp;
console.log(`Transaction Time: ${timeTaken}ms (${(timeTaken / 1000)} seconds)`);
const distanceMiles = 5473;
console.log(`Distance between Cambridge and San Francisco: ${distanceMiles} miles`);
const timeHours = timeTaken / (1000 * 60 * 60);
const speedMph = distanceMiles / timeHours;
console.log(`Stellar Cross Border Payments Speed: ${Math.trunc(speedMph).toLocaleString()} mph`);
const comparedToStarship = speedMph / 24600;
console.log(`That's ${Math.trunc(comparedToStarship).toLocaleString()} times faster than a SpaceX Starship!`);
});
} catch (e) {
console.log('An error has occurred:');
console.log(e.response.data);
if (e.response?.data?.extras?.result_codes) {
console.log('Result Codes:', e.response.data.extras.result_codes);
}
}
};
console.log(`
┏┓ ┓┓ ┏┓ ┓ ┏┳┓
┗┓╋┏┓┃┃┏┓┏┓ ┗┓┏┓┏┓┏┓┏┫ ┃ ┏┓┏╋
┗┛┗┗ ┗┗┗┻┛ ┗┛┣┛┗ ┗ ┗┻ ┻ ┗ ┛┗
┛
`);
init();
The script initializes with required modules and sets up a connection to the Stellar testnet via the Horizon API. It uses the Stellar SDK to create and sign a transaction for transferring 1 XLM, the native Stellar asset, from a source account to a receiver account.
The init
function defines the source secret key to derive the keypair and obtain the corresponding public key. It retrieves account details for the source account and fetches the current network base fee. A payment transaction is then constructed with the TransactionBuilder
, specifying the destination, asset type, and amount. The transaction is signed with the source keypair and submitted to the Stellar testnet.
The script logs timestamps for sending and receiving the transaction, allowing calculation of the confirmation time. Additionally, the user can manually input an external timestamp to measure transaction time further. It calculates the effective speed of cross-border payments by comparing transaction time to the distance between Cambridge and Portland, outputting the result as a speed in miles per hour.
Monitoring For Incoming Stellar Transactions
Now let’s look at how to set up an events monitor to check for incoming transactions.
const StellarSdk = require('stellar-sdk');
const receiverPubKey = 'GCG4VZZ6ZTYACRSTIHKXYEZENRAUFTKNGLE4XPQVCAZ7O5XM6W6PSVQI';
const server = new StellarSdk.Horizon.Server('https://horizon-testnet.stellar.org');
const handlePayment = (payment) => {
const receivedTimestamp = Date.now();
console.log(`Payment Received:`);
console.log(` From: ${payment.from}`);
console.log(` To: ${payment.to}`);
console.log(` Amount: ${payment.amount} ${payment.asset_type === 'native' ? 'XLM' : payment.asset_code}`);
console.log(` Explorer: https://stellar.expert/explorer/testnet/tx/${payment.transaction_hash}`);
console.log(` Timestamp: ${receivedTimestamp}`);
console.log('-----------------------------------');
};
console.log(`
┏┓ ┓┓ ┏┓ ┓ ┏┳┓
┗┓╋┏┓┃┃┏┓┏┓ ┗┓┏┓┏┓┏┓┏┫ ┃ ┏┓┏╋
┗┛┗┗ ┗┗┗┻┛ ┗┛┣┛┗ ┗ ┗┻ ┻ ┗ ┛┗
┛
`);
const es = server.payments()
.forAccount(receiverPubKey)
.cursor('now')
.stream({
onmessage: handlePayment,
onerror: (error) => {
console.error('Error in payment stream:', error);
}
});
console.log(`Listening for incoming payments...`);
This script listens for incoming payments on Stellar using the Stellar SDK. It targets a specified receiver account and streams payment events from the Horizon server.
When a payment is received, the handlePayment
function logs key details, including the sender, receiver, amount, and a link to view the transaction on Stellar Expert. It also records the timestamp of the event.
The streaming connection, initialized with the server.payments()
method, starts listening from the current point in time (cursor('now')
) when the script is run i.e. it’s not going to output past events.
Instructions
To get this up and running first install nodejs and run the following commands in a terminal
npm install
stellar keys generate --global test1 --network testnet --fund
stellar keys show test1
// then replace the secret key in the send.js file
node receive.js
// open up another terminal
node send.js
It will prompt you to enter the timestamp from receive.js terminal into the send.js terminal to calculate the transfer time.
I hope you’ve enjoyed this tutorial. If you want to learn more about Stellar and the Soroban smart contract platform there are some links below:
- Stellar Dev Portal: https://bit.ly/stellardevhub
- Stellar Dev Docs: https://bit.ly/stellardevdocs
- Stellar Dev Discord: https://bit.ly/stellar-discord-JB