Scripting PulseChain Testnet v2

In this article we show how transactions on the PulseChain Testnet v2 can be scripted in JavaScript using web3 module. For details on Ethereum JavaScript API read the reference documentation. Final script uses 2 addresses and shuffles always 50% of the bigger balances to the account with smaller balance until we ran out of gas.

Goal

The goal of this article is to demonstrate:

  • How to connect to PulseChain Testnet v2 (kudos Gamma for his PulseChain node and RPC service).
  • How a wallet and accounts (addresses) and private keys can be created (and insecurely stored).
  • How the current balance of an account can be checked.
  • How the tPLS transaction can be initiated and tracked.

Setup of runtime environment

First of all we need to create a simple NodeJS project environment, here we assume you have npm installed in your system:

npm install web3 
npm install axios

Now, lets create a wallet with 2 accounts between which we will shuffle the PLS balances. This scripts creates the wallet and saves it into wallet.json file in the current directory. You can run this script by executing node create-wallet.js:

'use strict';
const fs = require('fs');
const axios = require('axios')
const querystring = require('querystring')
const Web3 = require('web3');

const rpcNodeURL = 'https://testnetv2.pulserpc.io/rpc';
const walletFilePath = 'wallet.json';
const walletPassword = 'WouldNotGuess';

var web3 = new Web3(rpcNodeURL);

console.log("Creating new wallet with 2 accounts");
var wallet = web3.eth.accounts.wallet.create(2);

console.log("Saving wallet to", walletFilePath);
fs.writeFileSync(walletFilePath, JSON.stringify(wallet.encrypt(walletPassword)));

console.log("About to claim some tPLS from the faucet to the wallet account", wallet[0].address);
console.log("If the claim fails, send some tPLS manually there!");

axios({
	method: "POST", 
	headers: { "Content-Type": "application/x-www-form-urlencoded" },
	url: 'https://faucet.v2.testnet.pulsechain.com/api/claim',
	data: querystring.stringify({ address: wallet[0].address }),
}).then(
	response => { if(!response) return; console.log("Success - transaction:", response.data); }
).catch(
	error => { console.log("ERROR:", error.response.data); }
);

Main Script

The final script is below. You can run it by executing node balance-shuffler.js

'use strict';
const fs = require('fs');
const Web3 = require('web3');

const rpcNodeURL = 'https://testnetv2.pulserpc.io/rpc';
const walletFilePath = 'wallet.json';
const walletPassword = 'WouldNotGuess';
const web3 = new Web3(rpcNodeURL);

console.log('Loading wallet from', walletFilePath);
const wallet = web3.eth.accounts.wallet.decrypt(JSON.parse(fs.readFileSync(walletFilePath)), walletPassword);

const address1 = wallet[0].address
const address2 = wallet[1].address
console.log('About to shuffle balances between', address1, 'and', address2);

// web3.eth.getGasPrice().then(wei => { console.log('Gas price in wei:', web3.utils.fromWei(wei, 'gwei'), 'beats') });
// web3.eth.getBlockNumber().then(block => { console.log('Block:', block) })

async function waitForTransaction(transactionHash) {
	while(true) {
		let receipt = await web3.eth.getTransactionReceipt(transactionHash);
		if(receipt != null)
			return receipt;
		console.log('.');
		await new Promise(resolve => setTimeout(resolve, 100));
	};
}

// Selects address with bigger balance and transfers 50% of the balance to the other address
async function transferFromBigger(balance1, balance2) {
	let balance1PLS = web3.utils.fromWei(balance1, 'ether');
	let balance2PLS = web3.utils.fromWei(balance2, 'ether');

	let balancePLS =  balance1PLS > balance2PLS ? balance1PLS : balance2PLS;
	let addressFrom = balance1PLS > balance2PLS ? address1 : address2;
	let addressTo =   balance1PLS > balance2PLS ? address2 : address1;

	// round the 50% to avoid sending too small fractions, finally convert the value to string
	let credit = '' + Math.floor(balancePLS * 0.5 * 1e6) / 1e6;

	console.log('Balance of', addressFrom, 'is', balancePLS, 'tPLS. Sending', credit, 'to', addressTo);

	let transaction = await web3.eth.sendTransaction({
		from: addressFrom,
		to: addressTo,
		gas: 21000,
		value: web3.utils.toWei(credit, 'ether'),
	});
	console.log('  Transaction hash: ', transaction.transactionHash);

	console.log('  Waiting for transaction', transaction.transactionHash, 'receipt');
	await waitForTransaction(transaction.transactionHash);
}

// Checks balances of both the addresses
async function checkBalances() {
	let balance1 = await web3.eth.getBalance(address1, 'latest');
	let balance2 = await web3.eth.getBalance(address2, 'latest');
	return [balance1, balance2];
}

// Performs on pass of the main logic
async function checkAndTransfer() {
	try {
		let balances = await checkBalances();
		await transferFromBigger(balances[0], balances[1]);
		console.log(' Transaction succeeded');
	}
	catch(error) {
		console.log(' Transaction FAILED:', error);
		resolve();
	};
}

// Never-ending loop
async function doLoop() {
	await checkAndTransfer();
	setTimeout(doLoop, 0);
}

doLoop();