Programming Tutorial: Claiming Airdrops and Staking SPS (JavaScript/NodeJS)

avatar
(Edited)
Authored by @kiokizz

Intro

Practically every day for the last 4 months I have been manually claiming and staking my SPS airdrops. These happening across several accounts which I use to hold my Splinterlands assets has taken more hours than it would have, if I'd taken the time to automate it.

After reading @bauloewe's Python tutorials (Part 1 & Part 2) to do this, I decided to put these into JavsScript, so I can run them alongside some of my other utilities.

This script has been tested using NodeJS v16.13.0, though the same code should run through a browser page with the same packages imported. The airdrop claiming is limited to hive-engine/in-game assets, with game assets held on platforms such as WAX, Ethereum and Binance Smart Chain, requiring a different signature (a variation of Step 3).

Requirements

The following node modules will need to be installed. Each of the following links have instructions for installation using Node Package Manager(npm), as well as browser importing URLs.

Packages
axioshttps://www.npmjs.com/package/axios
hive-jshttps://www.npmjs.com/package/@hiveio/hive-js
eosjs-ecchttps://www.npmjs.com/package/eosjs-ecc

Into the Code

Importing our Modules

Step 1: Import

Our first step is to import the node modules. These can be grouped together at the top of our .js file.

// Modules
const axios = require('axios'); // npm i axios
const hive = require('@hiveio/hive-js'); // https://www.npmjs.com/package/@hiveio/hive-js
const ecc = require('eosjs-ecc') // https://www.npmjs.com/package/eosjs-ecc

Step 2: Configure

Our second step is to configure the hive account and run frequency. To sign the required transactions and broadcast to hive we will need a valid username and posting key for the player's Hive/Splinterlands account. The claim/stake frequencies can be adjusted, though to prevent unnecessary requests to the API, we will be using 5 minutes for our stake frequency, and 3 hours for our airdrop checking frequency.

// Configurations
let params = {
  username: `YOUR_USERNAME`,
  posting_key: `YOUR_PRIVATE_POSTING_KEY`,
  stake_frequency: 5,   // Minutes
  airdrop_frequency: 3  // Hours
}

Step 3: Claim

To Claim our airdrop, we'll write three functions:

  1. auto_claim_airdrop()
  2. login()
  3. claim_sps()

This first function, auto_claim_airdrop(), checks if the account has any airdrops unclaimed related to their HIVE wallet and (in-game) balances. The only required in our GET request is the accounts username.

async function auto_claim_airdrop() {
  setInterval(async () => {
    let url = `https://api2.splinterlands.com/players/sps?username=${params.username}`
    let response = await axios.get(url);
    let airdrops_array = response.data.airdrop;
    let claim_pending = airdrops_array.find(claim =>
    (claim.platform === `game` && claim.claim_tx === null)) !== undefined;
    if (claim_pending) login();
    else console.log(`No aidrops to claim.`)
  }, params.airdrop_frequency * 60 * 60 * 1000)
}

Our second function, login(), is called only when an airdrop is available to claim. The reason for logging in, which wasn't required during the first step, is to get login token used to claim our airdrop during the third function.

To log in, 3 parameters are required in our GET request to Splinterlands:

  1. name - @username
  2. ts - the current time in milliseconds
  3. sig - a string signed with the accounts posting key, generated using the above two strings.
async function login() {
  params.login_signature = ecc.sign(`${params.username}${params.ts}`, params.posting_key);
  params.ts = new Date().getTime();
  let url = `https://api2.splinterlands.com/players/login`
      + `?name=${params.username}`
      + `&ts=${params.ts}`
      + `&sig=${params.login_signature}`;
  let response = await axios.get(url);

  params.token = response.data.token;
  claim_sps();
}

Our third function, claim_sps(), submits the claim through another GET request, and reports whether it was successful, or whether an error has occured.

Six parameters are required:

  1. platform - hive
  2. address - @username
  3. sig - a string signed with the accounts posting key, using the platform, accounts username, and time string.
  4. ts - the current time in milliseconds (we reuse the time generated for our login)
  5. token - our loging token from earlier
  6. username - @username
async function claim_sps() {
  params.claim_signature = ecc.sign(`hive${params.username}${params.ts}`, params.posting_key);
  let url = `https://ec-api.splinterlands.com/players/claim_sps_airdrop`
      + `?platform=hive`
      + `&address=${params.username}`
      + `&sig=${params.claim_signature}`
      + `&ts=${params.ts}`
      + `&token=${params.token}`
      + `&username=${params.username}`
  let response = await axios.get(url);

  let data = response.data;
  if (data.success) {
    console.log(`Account ${data.data.to} successfully claimed ${data.data.qty} SPS.`
        + ` See transaction at hiveblocks.com/tx/${data.tx.id}`);
  } else console.log(`Error:`, data.error);
}

Step 4: Stake

To Stake our airdrop token, and continue claiming our SPS balance for that compound interest, we'll write three functions:

  1. auto_stake()
  2. get_balance()
  3. stake_sps(qty)

Our first function, auto_stake(), is a short and simple scheduling function. It initiates the other two functions immediately, then schedules them for the configured frequency.

async function auto_stake() {
  stake_sps(await get_balance());
  setInterval(async () => stake_sps(await get_balance()), params.stake_frequency * 60 * 1000);
}

Our second function, get_balance(), sends a GET request to Splinterlands with the account username, to get the current in-game balance. This is used as an input to the next function.

async function get_balance() {
  let url = `https://api2.splinterlands.com/players/balances?username=${params.username}`;
  let response = await axios.get(url);

  return response.data.find(currency => currency.token === `SPS`).balance;
}

Our third function submits our staking transaction to the HIVE Blockchain. A sample image of the output transaction is included:

image.png

function stake_sps(qty) {
  let json = {"token": "SPS", "qty": qty}
  hive.broadcast.customJson(
      params.posting_key, [], [params.username], `sm_stake_tokens`, JSON.stringify(json), function (err, res) {
        if (res) console.log(`Staked ${qty} tokens.`)
        else console.log(`Error Staking: ${err}`)
      });
}

Complete Code:

The following code is ready to run in NodeJS.

// Modules
const axios = require('axios'); // npm i axios
const hive = require('@hiveio/hive-js'); // https://www.npmjs.com/package/@hiveio/hive-js
const ecc = require('eosjs-ecc') // https://www.npmjs.com/package/eosjs-ecc

// Configurations
let params = {
  username: `YOUR_USERNAME`,
  posting_key: `YOUR_PRIVATE_POSTING_KEY`,
  stake_frequency: 5,   // Minutes
  airdrop_frequency: 3  // Hours
}

auto_claim_airdrop();
auto_stake();


// Airdrop Claim Functions
async function auto_claim_airdrop() {
  setInterval(async () => {
    let url = `https://api2.splinterlands.com/players/sps?username=${params.username}`
    let response = await axios.get(url);
    let airdrops_array = response.data.airdrop;
    let claim_pending = airdrops_array.find(claim => (claim.platform === `game` && claim.claim_tx === null)) !== undefined;
    if (claim_pending) login();
    else console.log(`No aidrops to claim.`)
  }, params.airdrop_frequency * 60 * 60 * 1000)
}

async function login() {
  params.ts = new Date().getTime();
  params.login_signature = ecc.sign(`${params.username}${params.ts}`, params.posting_key);
  let url = `https://api2.splinterlands.com/players/login`
      + `?name=${params.username}`
      + `&ts=${params.ts}`
      + `&sig=${params.login_signature}`;
  let response = await axios.get(url);

  params.token = response.data.token;
  claim_sps();
}

async function claim_sps() {
  params.claim_signature = ecc.sign(`hive${params.username}${params.ts}`, params.posting_key);
  let url = `https://ec-api.splinterlands.com/players/claim_sps_airdrop`
      + `?platform=hive`
      + `&address=${params.username}`
      + `&sig=${params.claim_signature}`
      + `&ts=${params.ts}`
      + `&token=${params.token}`
      + `&username=${params.username}`
  let response = await axios.get(url);

  let data = response.data;
  if (data.success) {
    console.log(`Account ${data.data.to} successfully claimed ${data.data.qty} SPS.`
        + ` See transaction at hiveblocks.com/tx/${data.tx.id}`);
  } else console.log(`Error:`, data.error);
}

// Auto Stake Functions
async function auto_stake() {
  stake_sps(await get_balance());
  setInterval(async () => stake_sps(await get_balance()), params.stake_frequency * 60 * 1000);
}

async function get_balance() {
  let url = `https://api2.splinterlands.com/players/balances?username=${params.username}`;
  let response = await axios.get(url);

  return response.data.find(currency => currency.token === `SPS`).balance;
}

function stake_sps(qty) {
  let json = {"token": "SPS", "qty": qty}
  hive.broadcast.customJson(
      params.posting_key, [], [params.username], `sm_stake_tokens`, JSON.stringify(json), function (err, res) {
        if (res) console.log(`Staked ${qty} tokens.`)
        else console.log(`Error Staking: ${err}`)
      });
}


0
0
0.000
5 comments
avatar
(Edited)

Hi @splinterstats (@kiokizz),

great tutorial. I never did much work with javascript just typescript so seeing how to auto claim sps with it is definitely interesting. Thanks for sharing :)

0
0
0.000
avatar

Congratulations @splinterstats! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s):

You distributed more than 12000 upvotes.
Your next target is to reach 13000 upvotes.

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

Check out the last post from @hivebuzz:

Christmas Challenge - 1000 Hive Power Delegation Winner
Merry Christmas - Challenge Feedback - Win a 1000 HP delegation
Support the HiveBuzz project. Vote for our proposal!
0
0
0.000
avatar

Hello,

Thank you for this, saved me some work! Btw, I made a step by step instruction for non techie here.

0
0
0.000