Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Intermediate · 30 minutes

Scheduling Transactions for Sending in the Future

If you plan to make a future payment in about 2 hours, 2days or 4 days time, you can achieve that by submitting the transaction in the future round. This allows an account to pay after an expected job is done or where an account balance is low and will be funded in a future date or time.

Requirements

  1. Javascript Algorand SDK
  2. The AlgoExplorer API

Background

Most transactions submitted immediately are process in the current round range of 1000 blocks. An account or dapp can decide to schedule a transaction outside the current block and will require this transaction to be saved and submitted. The signed transaction can be saved and submitted later via a cronjob or set a timeout for short term transaction in a single secure session.

Here is a quick video explaining the tutorial

Steps

1. Set up Algo SDK, mnemonic phrase and utility function

<script src="scripts/algosdk.min.js"></script>

//PUT YOUR MNEMONIC KEY HERE. 
 var mnemonic = "Mnemonic phrase";

// get account from the mnemonic phrase
let account = algosdk.mnemonicToSecretKey(mnemonic);

//get the address from the mnemonic phrase
address = account.addr;

//set the urls for retrieving params and posting to the algorand blockchain

const getParamsURL = "https://api.testnet.algoexplorer.io/v2/transactions/params";

const posturl = "https://api.testnet.algoexplorer.io/v2/transactions";

//Function to GET and POST transactions

    function getvals(fetchOption, url){

        return fetch(url,
        {
            method: fetchOption,
          headers: {
            'Content-Type': 'application/x-binary',
          },
        })
        .then((response) => response.json())
        .then((responseData) => {

          return responseData;
        })
        .catch(error => console.warn(error));
      }

1. Calculate future time to submit the transaction

You will need to calculate the difference in time it takes between the future transaction dateTime and the current time when the script is executed. Block production time on the chain is in seconds and it is better to calculate the difference in seconds.

// get the different in time between the future dateTime and now. 

// Change the date to a future date you prefer. It takes about 1:15 mins to complete the 1000 block rounds

    var futureTrxDate = "19 January 2021 17:20 UTC";
    var a = new Date(futureTrxDate);
    b = new Date();

   var diff_seconds = Math.abs(Math.round(((+b - +a) / 1000)));

2. Calculate Future Block Round

The average Algorand block production time is about 4.5. To get the total blocks or approximate last round reached by the future time, divide the time difference between future transaction date and now by the average block time of 4.5 seconds.

   var blockRound = Math.abs(Math.round(diff_seconds/4.5));

3. Calculate First AND Last Valid Rounds

Get the first and last valid rounds for the future transaction submission time

// get the parameters of the current block round
         fetchOption = "GET";
          url = "https://api.testnet.algoexplorer.io/v2/transactions/params";
      getvals(fetchOption,url).then(response=> {

        // get the last round of the current block, genesis id and genesis hash

        lastRound = response["last-round"];
        genesisID = response["genesis-id"];
        genesisHash = response["genesis-hash"]


        // get the first round of the future transaction date by adding the current last round to the future block round

        firstRoundFuture = lastRound + blockRound;

        // get the last round of the future transaction.
        // This is to make sure our transaction is
        // submitted even if there is a delay. 
        // Add 1000 round to the first round

        lastRoundFuture = firstRoundFuture + 1000;

4. Construct the Transaction Params

        // I realised the the Algorand genesis hash and
        // genesid ID don't change. So you can statically 
        //declare those

  let suggestedParams = {
       "flatFee": true,
       "fee": response.fee,
       "firstRound": firstRoundFuture,
       "lastRound": lastRoundFuture,
       "genesisID": genesisID,
       "genesisHash": genesisHash,
   };

// get the transaction details from the constants declared //for the future transaction

      var futureRecipient = "6NGU52ZU3XPRH5QJFBFG62H3FNGGGOHOSP462RICAFZCKII56ZMYEFV5UU";
       var amount = 1000000;
       var note =  algosdk.encodeObj("Invoice payment");

5. TimeOut or CronJob to Execute transaction

This step is important. Since this is a future transaction, you need to execute this script during the future round period. For the purpose of this tutorial and for convinience, I use the Timeout function to delay the script from submitting the transaction until the round passes. The script executes in millisecons and so I multiply the seconds by 1000 to give the milliseconds to timeout.

    timeOutTime = diff_seconds*1000;

6. Process the Transaction

   let txn = algosdk.makePaymentTxnWithSuggestedParams(address, futureRecipient, amount, undefined, note, suggestedParams);
     let signedTxn = txn.signTxn(account.sk);
     console.log(signedTxn);

    **setTimeout**(()=> {    fetch(posturl, {
      method: 'POST', // or 'PUT'
       headers: {
        'Content-Type': 'application/x-binary',
       },
       body: signedTxn,
     })
     .then(response => response.json())
     .then(data => {
       console.log(data);

     })
     .catch((error) => {
       console.error('Error:', error);
     });

    }, **timeOutTime**);



    });

  </script>