Set up Azure Service Health Alerts programmatically using PowerShell

The Azure Service Health team has been working hard to make it easy for you to set up custom service health alerts for your Azure resources. While we primarily focus on user experiences in the portal, we also know that there are many power users who are interested in doing these same actions in a programmatic way.

This post will walk you through the steps required to programmatically create a service health alert using Azure Resource Manager templates and Azure PowerShell.

As described here, you can create any kind of activity log alert using this method (Administrative, Autoscale, Recommendation, etc…), however for the purposes of clarity, we will specifically focus on service health alerts.

Getting Started

Before you can follow this tutorial, you must have Azure PowerShell installed on your system. This will give you access to the AzureRM module, which is needed to interact with your Azure subscription.

You can follow the instructions here to install Azure PowerShell.

Creating an ARM Template for Service Health Alerts

A service health alert is represented by JSON which is stored in your Azure subscription, and follows rules defined by Azure’s internal system. This JSON is also referred to as the Azure Resource Manager template. You can find an example of a general Activity Log Alert template here.

For service health alerts, we should use a template like this:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "activityLogAlertName": {
      "type": "string",
      "metadata": {
        "description": "Unique name (within the Resource Group) for the Activity log alert."
      }
    },
    "activityLogAlertEnabled": {
      "type": "bool",
      "defaultValue": true,
      "metadata": {
        "description": "Indicates whether or not the alert is enabled."
      }
    },
    "actionGroupResourceId": {
      "type": "string",
      "metadata": {
        "description": "Resource Id for the Action group."
      }
    }
  },
  "resources": [   
    {
      "type": "Microsoft.Insights/activityLogAlerts",
      "apiVersion": "2017-04-01",
      "name": "[parameters('activityLogAlertName')]",      
      "location": "Global",
      "kind": null,
      "tags": {},
      "properties": {
        "enabled": "[parameters('activityLogAlertEnabled')]",
        "description": "",
        "scopes": [
            "[subscription().id]"
        ],        
        "condition": {
          "allOf": [
            {
              "field": "category",
              "equals": "ServiceHealth",
              "containsAny" : null
            }
          ] 
        },
        "actions": {
          "actionGroups": 
          [
            {
              "actionGroupId": "[parameters('actionGroupResourceId')]",
              "webhookProperties": {}
            }
          ]
        }
      }
    }
  ]
}

You should save this file as servicehealthalert.json.

A quick note on generating custom ARM templates

I would assume that most of you reading this post do not want or need to start from scratch. Instead, you know what you want to achieve using the Azure portal UX, and you simply want to automate that process. In that case, there is an easy way for you to generate a custom ARM template for your needs:

  1. Go to the Health Alerts section in Azure Service Health
  2. Create a new service health alert
  3. Take note of the resource group you save the alert in
  4. Then go to the Azure Resource Explorer
  5. Navigate to: subscriptions > (subscription) > resourceGroups > (resourceGroup) > providers > microsoft.insights > activityLogAlerts > (alertName)
  6. You will find a JSON representation of your alert with all your custom conditions
  7. Copy those extra conditions into the template above

Examples of Custom Conditions

The template provided above is a very broad service health alert that will be triggered whenever any activity log with the category ServiceHealth is created. However, using this same JSON template, you can further specify what kinds of events you want to be alerted for:

  • Only be notified for certain Azure services
  • Only be notified for certain regions
  • Only be notified for certain health alert types

Note that there are over 122 Azure services, across more than 28 regions, so your JSON can start to get a little messy if you try to hand type it all out. I recommend you follow the instructions above on generating custom ARM templates.

Here is an example of an ARM template that takes advantage of all 3 of these conditions:

{
   "$schema":"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
   "contentVersion":"1.0.0.0",
   "parameters":{
      "activityLogAlertName":{
         "type":"string",
         "metadata":{
            "description":"Unique name (within the Resource Group) for the Activity log alert."
         }
      },
      "activityLogAlertEnabled":{
         "type":"bool",
         "defaultValue":true,
         "metadata":{
            "description":"Indicates whether or not the alert is enabled."
         }
      },
      "actionGroupResourceId":{
         "type":"string",
         "metadata":{
            "description":"Resource Id for the Action group."
         }
      }
   },
   "resources":[
      {
         "type":"Microsoft.Insights/activityLogAlerts",
         "apiVersion":"2017-04-01",
         "name":"[parameters('activityLogAlertName')]",
         "location":"Global",
         "kind":null,
         "tags":{

         },
         "properties":{
            "enabled":"[parameters('activityLogAlertEnabled')]",
            "description":"",
            "scopes":[
               "[subscription().id]"
            ],
            "condition":{
               "allOf":[
                  {
                     "field":"category",
                     "equals":"ServiceHealth",
                     "containsAny":null
                  },
                  {
                     "field":"properties.incidentType",
                     "equals":"Informational",
                     "containsAny":null
                  },
                  {
                     "field":"properties.incidentType",
                     "equals":"ActionRequired",
                     "containsAny":null
                  },
                  {
                     "field":"properties.impactedServices[?(@.ServiceName == 'Advisor' || @.ServiceName == 'Alerts & Metrics' || @.ServiceName == 'App Service')].ImpactedRegions[*].RegionName",
                     "equals":null,
                     "containsAny":[
                        "Australia East",
                        "Brazil South",
                        "Canada East",
                        "Central US"
                     ]
                  }
               ]
            },
            "actions":{
               "actionGroups":[
                  {
                     "actionGroupId":"[parameters('actionGroupResourceId')]",
                     "webhookProperties":{

                     }
                  }
               ]
            }
         }
      }
   ]
}

The ARM template is actually pretty powerful in terms of the logic that it can resolve. You are not limited to only these 3 options when customizing the alert. You can pretty much add logic to any attribute which exists in the activity log. However, if you customize the JSON template too much, you might break the UX in the Azure portal. This is not a big deal, but can cause problems loading the alert in the portal, and if you do ever update the alert in the portal, you will likely lose all of your custom logic.

Creating a new alert using PowerShell

Now that you have your ARM template created, creating a new activity log alert in your subscription is relatively easy. Using the AzureRM module, run the following:

Login-AzureRmAccount

Select-AzureRmSubscription -SubscriptionName <subscription_name>

New-AzureRmResourceGroupDeployment -Name ExampleDeployment -ResourceGroupName <resource_group> -TemplateFile <path:\to\servicehealthalert.json>

You should then be prompted to type in the Alert Name and the Action Group Resource ID:

Supply values for the following parameters:
(Type !? for Help.)
activityLogAlertName: <Alert Name>
actionGroupResourceId: /subscriptions/<subscriptionId>/resourceGroups/<resouceGroup>/providers/microsoft.insights/actionGroups/<actionGroup>

If there are no errors, you should get the following confirmation in PowerShell:

DeploymentName          : ExampleDeployment
ResourceGroupName       : <resourceGroup>
ProvisioningState       : Succeeded
Timestamp               : 11/8/2017 2:32:00 AM
Mode                    : Incremental
TemplateLink            :
Parameters              :
                          Name                     Type       Value
                          ===============          =========  ==========
                          activityLogAlertName     String     <Alert Name>
                          activityLogAlertEnabled  Bool       True
                          actionGroupResourceId    String     /subscriptions/<subscriptionId>/resourceGroups/<resouceGroup>/providers/microsoft.insights/actionGroups/<actionGroup>

Outputs                 :
DeploymentDebugLogLevel :

And that is it! You can now stay fully informed when Azure service issues affect you.

Programmatically fetch multiple APIs in parallel using async and await in JavaScript

When I was building ethfolio, I had to figure out how to retrieve the token information for multiple Ethereum addresses. To get this information, you have to query an API per address that you want to retrieve.

Ideally, all of these calls would happen Asynchronously and in parallel, to give theΒ  best and fastest experience to the user. However, how exactly to do this is not so obvious (to me at least).

Let’s assume that you have an array of URLs that you want to fetch at the same time. You can use an asynchronous function like this to easily retrieve all the data in the best way possible:

async function getAllUrls(urls) {
    try {
        var data = await Promise.all(
            urls.map(
                url =>
                    fetch(url).then(
                        (response) => response.json()
                    )));

        return (data)

    } catch (error) {
        console.log(error)

        throw (error)
    }
}

This function will return an array of ‘responses’ which you can then use for the rest of your program. Calling the function is simple too!

var responses = await getAllUrls(urls)

Ultimately the trick here is that a Promise gets executed as soon as it gets created. The map function will create all the fetch promises and they will immediately start to execute. Then, we wait for all the promises to complete using the Promise.all function.

I tried other ways to construct this kind of function, but none were quite as simple or effective as this. I hope you find this helpful πŸ™‚

ethfolio: A client side app to show your Ethereum token distribution

A common question that I have for others investing in cryptocurrencies is: “What coins are you invested in?”

It is surprisingly hard to distinguish fear, uncertainty, doubt (FUD), fear of missing out (FOMO), and solid informed advice apart from one another. But as the saying goes:

Put your money where your mouth is.

This is the goal of ethfolio:

  • Allow users to easily import the coins they currently are holding
  • Allow users to share this token distribution
  • And do so safely without needing to expose their Ethereum addresses or total value of their holdings

This actually seemed very straightforward, so I decided to tackle the project. Rather than go through all the work to actually query the blockchain as I have been learning to do in my other posts, I decided to just use an API which consolidates all this information.

Ethplorer.io was perfect for this. They have a /getAddressInfo/ api endpoint which provides details about the tokens at an Ethereum address, and even details about those tokens like the price in USD.

This was perfect! So I begin to envision the user story:

  1. User goes to ethfolio, types in one or more Ethereum addresses
  2. User presses a “submit” button
  3. In the background we query the Ethplorer API to get all the tokens across all the addresses, and their current price in USD
  4. We then add up total amount of each token the user has across their wallets
  5. Then, we use the price information, to calculate the relative USD price of each token balance
  6. Then we calculate the total USD price across all balances, to find the percentage a particular token represents in the overall portfolio
  7. Display the results

Following this process, the user can then share details about their token distribution without ever needing to share details about their specific addresses (which is important for anonymity) and without needing to share details about the total balance they hold (which could be sensitive to the user.)

With these steps in mind, I spent a day and created this pretty quickly:

http://shawntabrizi.com/ethfolio/

You may notice that there are some options to “Store total USD value” and “Store all addresses”. Lets talk about what I tried to do with “Save & Share”.

I wanted this to be a completely client side application. This means I don’t have to do any server stuff,Β  the user can better trust the application (because they can see all the code), and calling the API would come from each user, so I wouldn’t get throttled if the site takes off. My question then was: “How can I create a database for a client side application?”

This means that writing and reading from the database needs to be in such a way that it won’t compromise the data being stored. My first thought was to try and use Google Forms/Sheets. Google Forms is a method for publicly entering data, which can get stored into a Google Sheet which can be publicly viewed. Using Google’s authorization layer, I could make it so that users could not edit the sheet, only add data to it, and read from it.

I got the part of the app to write to Google working. It doesn’t look pretty because the app gives a CORS error, but Google seems to accept the data anyway.

Ignore the error

Cause data gets saved anyway…

However, I was not able to ever retrieve this data! Even though this sheet is public, it seems like to call any of Google’s APIs you must be authenticated, at least with an API key.

I created an API key, but trying to use it I get this error:

"message": "API Key not found. Please pass a valid API key."

Every API key is associated with a “Google App Project”, and I needed to specifically enable the Google Sheets API for the project where I was creating the API key.

Now that this call works, I just need to build an interface to read from the sheet, and re-display the data! That will be coming up next!

Making Web3.js work asynchronously with JavaScript Promises and await

One of the things I learned when writing my “Hello World” tutorial for Ethereum and Web3.js was the importance of having your functions which call the blockchain run asynchronously. Without this, we would be unable to support users who use MetaMask as their Ethereum provider, and probably even more important, we may bring bad user experiences by locking up the browser during long HTTP requests. From the MetaMask developer FAQ:

Using synchronous calls is both a technical limitation and a user experience issue. They block the user’s interface. So using them is a bad practice, anyway. Think of this API restriction as a gift to your users.

Setting up a Web3 function to work asynchronously was pretty easy to figure out for a single call; but what about making multiple calls through Web3, that all need to be asynchronous, but also have dependencies on one another?

An example would be calculating the ERC-20 token balance of an Ethereum address. To do this, you need to know both the balance of tokens at the address, but also the decimals value for that token to convert to the right units. JavaScript Promises are the natural solution here. They allow you to track the status of an asynchronous function, and perform actions after your multiple dependencies all resolve.

Turning Web3.js functions into JavaScript Promises

In my “Hello World” tutorial, I show you can make an asynchronous requests by adding an error first callback to the Web3.js functions:

web3.eth.getBalance(address, function (error, result) {
    if (!error) {
        console.log(result);
    } else {
        console.error(error);
    }
});

As I mentioned, if we depend on multiple calls from the Ethereum blockchain to create a result, using JavaScript Promises is a good solution. They allow you to react to a success or a failure from an asynchronous function. Creating a promise from the error first callback function is pretty straightforward:

function getBalance (address) {
  return new Promise (function (resolve, reject) {
    web3.eth.getBalance(address, function (error, result) {
      if (error) {
        reject(error);
      } else {
        resolve(result);
    }
  })
}

But we can actually make this process even simpler for multiple Web3 functions by creating a wrapper which both makes the function asynchronous, and turn it into a promise; basically automating what we would repeat above for each different Web3 function we call.

Here is the wrapper from 0xcaff posted in StackExchange:

const promisify = (inner) =>
    new Promise((resolve, reject) =>
        inner((err, res) => {
            if (err) {
                reject(err);
            } else {
                resolve(res);
            }
        })
    );

Now that we have a Promise, we can take advantage of the async/await pattern which simplifies not only the look, but also the behavior of Promises.

Putting this all together, let’s show how simple this makes getting the token balance for an ETH account. We convert our original “Hello World” getBalance into an asyncronous function, like so:

async function getBalance() {
    var address, wei, balance
    address = document.getElementById("address").value;
    wei = promisify(cb => web3.eth.getBalance(address, cb))
    try {
        balance = web3.fromWei(await wei, 'ether')
        document.getElementById("output").innerHTML = balance + " ETH";
    } catch (error) {
        document.getElementById("output").innerHTML = error;
    }
}

Not much shorter for a single function, but will certainly make things better the more separate functions we call. My next post will show the results of these smaller educational posts, and how we can put it together to create the project I have been hinting above: Getting the ERC-20 balance of an Ethereum Address.

I hope this teaches you something! Again, this may be trivial to many, but was not so straightforward when I first started to tackling these problems. If it did help you, feel free to support me with a small donation here:

0xD62835Fe2B40C8411A10E7980a290270e6A23cDA

Ethereum Token Contract ABI in Web3.js for ERC-20 and Human Standard Tokens

This post will introduce you to Token Contract ABIs in Ethereum, and show you how you can use a the Human Standard Token ABI to access the token balances of ERC-20 compatible tokens.

 

Let me start by saying that this post may be trivial to some, but was very confusing to me, a brand new user to the Ethereum and Web3.js development world. After writing my “Hello World” project which gets the ETH balance for an Ethereum Address in Web3, I began to think about the next small step I can take and teach to others. Naturally, I thought it would make sense to do a similar project, but instead, get the Token Balance for ERC-20 tokens at an Ethereum Address.

With Web3.js, you can easily find the template for this functionality:

var tokenContract = eth.contract(tokenABI).at(tokenAddress);
var tokenBalance = tokenContract.balanceOf(ethereumAddress);

Seems easy enough to get the Token Address, but what is this tokenABI value that we need to use?

A simplified explanation of a token contract ABI

A little bit of searching will give you documents that teach you about the Application Binary Interface (ABI) like this, but no real layman’s terms explanation. Here is my attempt at one:

In Ethereum, the Application Binary Interface (ABI) is a predefined template of the functions a contract exposes.

You know when you import a new library into an IDE, you automatically get all that nice autocomplete and Intellisense? You type the library name, add “.” and a list of functions appears in front of you:

Imagine if instead, you needed to know ahead of time the functions the library exposes, and then define them for the IDE so that the autocomplete would work… that is pretty much what is happening here.

An Ethereum Contract ABI will define the different functions that a contract exposes, and each function definition will contain things like the function type, name, inputs, outputs, and more. It even contains information like whether the contract accepts payments in ether or not. Here is the JSON ABI of the balanceOf() function we ultimately want to use:

{
  "constant": true,
  "inputs": [
    {
      "name": "_owner",
      "type": "address"
    }
  ],
  "name": "balanceOf",
  "outputs": [
    {
      "name": "balance",
      "type": "uint256"
    }
  ],
  "payable": false,
  "type": "function"
}

I think this is easy enough to read: It is a function which accepts an address as an input, and outputs a balance as an unsigned int. But is this enough to start talking to an Ethereum contract? What about all the other functions that contract might have? How will I find the full contract ABI for each contract I want to talk to?

Here are the things I learned when trying to answer these questions:

  • You do NOT need the full ABI to interact with a Token Contract. You only need to define the functions which you want to use.
  • You cannot programmatically generate the ABI for a given contract using data from the Ethereum blockchain. In order to generate the full contract ABI from scratch, you will need the full contract source code, before it is compiled. Note that only the compiled code exists at a contract address.
  • Some contracts have functions which are intentionally ‘hidden’ from the public, and they do not intend the public to use.

Therefore, there really is no way to dynamically call any contract address. If only there were some standard set of functions shared across all contracts…

The ERC-20 and Human Standard Token

From the specification:

Simple Summary

A standard interface for tokens.

The value of ERC-20 tokens is that they all have a standard set of functions which allow you to interact with each of them in the exact same way. This is why there is so much hype around new Ethereum application which use ERC-20 tokens: there is nearly zero effort to add these tokens to existing platforms like Cryptocurrency Exchanges which means smoother adoption, easier to sell/track, and of course more hype ($$$).

What does it take to be ERC-20 compliant?

Not much really. You just need to expose the non-optional methods and events described here. Beyond the core ERC-20 standard, there are also standard optional parameters which are intended for humans. See here:

In other words. This is intended for deployment in something like a Token Factory or Mist wallet, and then used by humans.
Imagine coins, currencies, shares, voting weight, etc.
Machine-based, rapid creation of many tokens would not necessarily need these extra features or will be minted in other manners.

1) Initial Finite Supply (upon creation one specifies how much is minted).
2) In the absence of a token registry: Optional Decimal, Symbol & Name.
3) Optional approveAndCall() functionality to notify a contract if an approval() has occurred.

This is the “Human Standard Token”, which of course is a super-set of the ERC-20 standard. Additionally, many tokens have a version() function which is also available in the ABI provided below.

So let’s get it working!

Now that you have sufficient background to understand what is going on, lets actually go and make some calls to ERC-20 token contracts.

To start, you can find the Human Standard Token ABI here on GitHub. The JS file simply puts the ABI JSON object into a varaible called human_standard_token_abi which allows you to really easily use it in a project.

The most basic project that can take advantage of these things would look something like this:

<html>
<head>
  <meta charset="UTF-8">
  <script type="text/javascript" src="./web3.min.js"></script>
  <script type="text/javascript" src="./human_standard_token_abi.js"></script>
  <script>
    var web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/<APIKEY>"));

    address = "0x0e2e75240c69495d2b9e768b548db381de2142b9" //From Etherscan
    contractAddress = "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07" //OMG
    contractABI = human_standard_token_abi

    tokenContract = web3.eth.contract(contractABI).at(contractAddress)

    console.log(tokenContract.balanceOf(address).toNumber())
  </script>
</head>
<body>
  <p>Check the console (F12)</p>
</body>
</html>

And the output:

What if…

Let’s try a few fringe scenarios with this contract ABI. We will be testing this against OmiseGo.

  • What if we call a contract with a function we defined, but does not exist on the contract?

OMG does not have a version() function, but we define it by default in our human_standard_token_abi. So let’s call it:

console.log(tokenContract.version())

“Uncaught Error: new BigNumber() not a base 16 number”

  • What if we call a contract with a function that exists, but we did not define in the ABI?

OMG has the function mintingFinished() which is not part of the Human Standard Token ABI. If we call it, we get the following error:

“Uncaught TypeError: tokenContract.mintingFinished is not a function”

 

What I hope you learned:

  • The requirements to call an ERC-20 compliant token contract using Web3.js
  • What a Token Contract ABI is on the Ethereum Blockchain
  • Why the ERC-20 standard is pretty great for develeopers
  • How to easily add the human_standard_token_abi to your JavaScript web application

Keep an eye out for my next post, which will detail how to set up Web3.js for JavaScript promises, so we can execute multiple Web3 functions asynchronously. Then we will take both of these pieces, and make a simple web app that can fetch the ERC-20 token balance at an Ethereum address.

If you liked this post, and want to support me, feel free to send donations here:

0xD62835Fe2B40C8411A10E7980a290270e6A23cDA

Correcting the Ethereum and Web3.js “Hello World”

Just 2 days ago I blogged about a quick project which I considered a “Hello World” application for Ethereum and Web3.js. However, I quickly learned that even in my short 31 lines of code, I made numerous mistakes which do not follow the best practices for developing Web3.js applications.

The main part of the sample was the Web3.js stuff, which could be broken into two logical sections:

  1. Establishing a Web3 Provider
  2. Getting the ETH balance of an Ethereum Address

Both of these sections had mistakes in my original code, and this post will show you how to fix them! I will be updating the main blog post to include these changes as well, but I wanted to document the subtleties of the changes, and what I have learned since then. BTW, all of these mistakes could be avoided if you read the MetaMask developer documentation.

Ethereum Browser Environment Check

In my original sample, I simply depend on the Web3 HTTP Provider to access the Ethereum network. However, using MetaMask or the Mist Browser, users will already have direct access to the Ethereum network through those providers, and do not need to use the HTTP Provider. As said in the Web3 JavaScript app API Documentation:

…you need to create a web3 instance, setting a provider. To make sure you don’t overwrite the already set provider when in mist, check first if the web3 is available…

To fix this, we mostly follow the code sample provided by MetaMask:

window.addEventListener('load', function () {
    if (typeof web3 !== 'undefined') {
        console.log('Web3 Detected! ' + web3.currentProvider.constructor.name)
        window.web3 = new Web3(web3.currentProvider);
    } else {
        console.log('No Web3 Detected... using HTTP Provider')
        window.web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/noapikey"));
    }
})

As they mention on the MetaMask developer documentation:

Note that the environmental web3 check is wrapped in a window.addEventListener('load', ...) handler. This approach avoids race conditions with web3 injection timing.

With our new code, as soon as the page loads, we detect if the browser being used already has a Web3 provider set up, and if it does we use it! Otherwise, we will use the HTTP Provider from Infura.io. For most users, I would assume they do not have MetaMask, and thus this change is not very important; but it is certainly best practice, and I am happy to oblige.

Chrome with MetaMask:

Firefox without Web3 Provider:

Asynchronous calls to the Ethereum network

If you have been following along word for word, you might have copied the changes mentioned above, loaded it in your MetaMask enabled browser (from your web server), and tried to get your ETH balance… Here is what you will see:

If we continue to read the MetaMask developer documentation, we would see the following:

The user does not have the full blockchain on their machine, so data lookups can be a little slow. For this reason, we are unable to support most synchronous methods.

This means we need to turn our call to get the ETH balance, which is currently a synchronous HTTP request, into an asynchronous request. We can do this by adding an error first callback as the last parameter of the function:

function getBalance() {
    var address, wei, balance
    address = document.getElementById("address").value
    try {
        web3.eth.getBalance(address, function (error, wei) {
            if (!error) {
                var balance = web3.fromWei(wei, 'ether');
                document.getElementById("output").innerHTML = balance + " ETH";
            }
        });
    } catch (err) {
        document.getElementById("output").innerHTML = err;
    }
}

If we try to run this code now with MetaMask as our provider, everything works again!

The first, but certainly not last mistake…

Phew! We fixed our Hello World application! Take a look at the overall changes on GitHub. I think this goes to show how difficult it can be to learn things on your own, and some of the best practices that can be overlooked so easily. I hope that I am able to go through these issues so that you don’t have to. If you find any other issues with this or future samples I create, please let me know!

Special shout out to Reddit user JonnyLatte for telling me the errors in my ways, and getting me to read more of the documentation around Web3!

As always, if you found this content helpful, feel free to show some appreciation at this address: 0xD62835Fe2B40C8411A10E7980a290270e6A23cDA

Ethereum and Web3.js “Hello World”: Get the ETH Balance of an Ethereum Address

Using just 41 lines of HTML + JS, we create a Web3.JS application which can get the ETH Balance of an Ethereum Address [Final Result] [GitHub]

 

For me, the hardest part of learning new technical skills is overcoming the hurdle of simply getting started. The Ethereum development space is booming, and the ability to make relatively simple web applications that interact with the Ethereum blockchain is at a premium. Today, development on World Wide Web requires you to compete with a huge number of fully developed, feature rich applications, where it is very unlikely that you are actually contributing value. However, the same is absolutely not true for Ethereum and blockchain as a whole. There are so many utilities and tools that can bring value to this ecosystem, all with relatively low feature requirements.

So let’s overcome the first barrier by building a “Hello World” application.

From my perspective, the perfect project for something like this would be a bare-bones single-page application which fetches the ETH balance of an Ethereum address. This is about as simple as it gets to allow a user to interact with the blockchain, and thanks to Web3.js, it is also really simple to implement!

Prerequisites

To gain access to the Ethereum network, you will need to gain access to a Web3 Provider. As I will talk about more below, this comes natively with certain Ethereum focused browsers, but for the average user you will need to provide them with their own gateway to the blockchain. Basically, you need someone to provide your app the data that is actually on the blockchain, and Web3.js has the ability to interact directly with an HTTP Provider to bring you this data with minimal effort.

I used Infura.io as my Ethereum provider (for no other reason than they showed up first when searching), and after spending less than a minute registering with them for free, I was given my unique address to their Main Ethereum Network where my API Key was appended at the end.

Save this URL, as you will be using it very shortly.

https://mainnet.infura.io/<APIKEY>

The only other thing you need to get started is your own copy of Web3.js which can be found on GitHub. Just download and unpack the ZIP file.

Create a new folder where you want your project to live, and create an index.html file. Then, from the Web3.js download, copy web3.min.js to that folder.

ethbalance/     (folder)
β”œβ”€β”€ index.html
└── web3.min.js

Finally, make sure you initialize your index.html skeleton:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>

<body>
</body>
</html>

Let’s get started!

To make this as simple as possible, we are going to create a single HTML file which will contain all the code necessary to complete this project. It will be broken into 2 parts:

  1. HTML to render a bare-bones web page
  2. JavaScript to initialize a Web3 object, and interact with our HTTP Provider

HTML Body

Our HTML body needs a text field for the user to input an Ethereum address, a button to trigger the JavaScript, and an output area to display the result. I am going to assume that if you are reading this post, you have enough familiarity with HTML that I can just breeze over this, and give you the code:

<body>
    <h1>ETH Balance Fetcher</h1>
    <p>Enter your Ethereum Address:</p>
    <input type="text" size="50" id="address" />
    <button type="button" onClick="getBalance();">Get Balance</button>
    <br />
    <br />
    <div id="output"></div>
</body>

The only thing of note here is that when you click the button we created, it triggers a JavaScript function getBalance(), and that is what we are going to write next!

HTML Head: JavaScript and Web3

Now it is time to prepare the JavaScript required to make this all work. We are going to need to get the Ethereum address inputted by the user, initiate our connection to the Ethereum Provider, and then query the blockchain for the ETH balance at that address. Oh, of course we will also send back the result and update the HTML with the value. Here is our HTML head template:

<head>
    <!-- Check if Web3 already defined -->
    <!-- If not, connect to HTTP Provider -->
    <!-- getBalance() function -->
</head>

First we will load and set up our Web3 provider. If you are using an Ethereum compatible browser like Brave, Chrome + MetaMask, or Mist, you will already have your own Web3 provider established natively. You can access that connection with this:

<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="./web3.min.js"></script>
    <script type="text/javascript">
        window.addEventListener('load', function () {
            if (typeof web3 !== 'undefined') {
                console.log('Web3 Detected! ' + web3.currentProvider.constructor.name)
                window.web3 = new Web3(web3.currentProvider);
            }
        })

    <!-- If not, connect to HTTP Provider -->
    <!-- getBalance() function -->
    </script>
</head>

 

More likely, the user does not have one of these browsers, so we need to establish our own connection to the Ethereum network. We can do this with the URL that you saved earlier from Infura.io, and establishing an HTTP Provider:

<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="./web3.min.js"></script>
    <script type="text/javascript">
        window.addEventListener('load', function () {
            if (typeof web3 !== 'undefined') {
                console.log('Web3 Detected! ' + web3.currentProvider.constructor.name)
                window.web3 = new Web3(web3.currentProvider);
            } else {
                console.log('No Web3 Detected... using HTTP Provider')
                window.web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/<APIKEY>"));
            }
        })

    <!-- getBalance() function -->
    </script>
</head>

At this point, we can do just about anything that Web3.js offers, but for our purposes we only need to query the blockchain for the address, and return the ETH balance. So let’s set up our getBalance() function:

<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="./web3.min.js"></script>
    <script type="text/javascript">
        window.addEventListener('load', function () {
            if (typeof web3 !== 'undefined') {
                console.log('Web3 Detected! ' + web3.currentProvider.constructor.name)
                window.web3 = new Web3(web3.currentProvider);
            } else {
                console.log('No Web3 Detected... using HTTP Provider')
                window.web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/<APIKEY>"));
            }
        })
        function getBalance() {
            var address, wei, balance
            address = document.getElementById("address").value
            try {
                web3.eth.getBalance(address, function (error, wei) {
                    if (!error) {
                        var balance = web3.fromWei(wei, 'ether');
                        document.getElementById("output").innerHTML = balance + " ETH";
                    }
                });
            } catch (err) {
                document.getElementById("output").innerHTML = err;
            }
        }
    </script>
</head>

Walking through the function:

First we store the value of the text field from our HTML page into the address variable. Then, we will try to use the web3 object we intialized earlier to call the function web3.eth.getBalance() which accepts an Ethereum Address as an input. Note that we need to make this call asynchronously as the user does not have the full blockchain loaded on their machine, so some calls may run slow. Rather than lock the user’s interface, we let the the call happen in the background, and when it is complete, we trigger an update to the page. This is required to support MetaMask, but benefits all Web3 applications. If you want to learn more about how to make these requests asynchronous, take a look at the “Using callbacks” section in the Web3 documentation.

Once the asynchronous request is complete, we will get back a Wei balance as a result. But we want the Ether value, so we do one last step to convert the value: web3.fromWei(wei, 'ether'). If all of this is successful, we update the output div with our result, otherwise if it fails at any point we catch the error, and output that message instead.

Here is the final index.html file which you should be able to use as soon as you paste in your <APIKEY> from Infura.io. You can also download this project directly from my GitHub.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="./web3.min.js"></script>
    <script type="text/javascript">
        window.addEventListener('load', function () {
            if (typeof web3 !== 'undefined') {
                console.log('Web3 Detected! ' + web3.currentProvider.constructor.name)
                window.web3 = new Web3(web3.currentProvider);
            } else {
                console.log('No Web3 Detected... using HTTP Provider')
                window.web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/<APIKEY>"));
            }
        })
        function getBalance() {
            var address, wei, balance
            address = document.getElementById("address").value
            try {
                web3.eth.getBalance(address, function (error, wei) {
                    if (!error) {
                        var balance = web3.fromWei(wei, 'ether');
                        document.getElementById("output").innerHTML = balance + " ETH";
                    }
                });
            } catch (err) {
                document.getElementById("output").innerHTML = err;
            }
        }
    </script>
</head>
<body>
    <h1>ETH Balance Fetcher</h1>
    <p>Enter your Ethereum Address:</p>
    <input type="text" size="50" id="address" />
    <button type="button" onClick="getBalance();">Get Balance</button>
    <br />
    <br />
    <div id="output"></div>
</body>
</html>

You can try this out right now using the version I hosted here: http://shawntabrizi.com/ethbalance/

One thing you should note is that this is a client-side JavaScript application. There are a million reasons why making client-side apps is so much easier for development, but one big downside is that your API key will be exposed to anyone who simply inspects the HTML. Please do not abuse my API key, and please do not ship a production application using a method like this unless you are prepared to get your API key terminated.

Note that I have made updates to this blog post, correcting some issues regarding best practices with Web3. You can learn more about the errors I made along the way here.

I hope this helps you get started with developing for Ethereum using Web3.js! If you liked this content, and want to support me, feel free to send donations to this address: 0xD62835Fe2B40C8411A10E7980a290270e6A23cDA

Getting started with Ethereum Wallet

Well, Cryptocurrencies have consumed my attention for the past 5 months. I first learned about Etherum back in May when I was attending a Bachelor party. Since then, I have been a relatively hands off investor, but it is time to actually start contributing and learning about the development platform.

To start, we need to install the Etherum Wallet, which also downloads the entire Etherum chain, which as of this post is over 4.3 million blocks long. The unfortunate part of this process is that it takes a lot of disk space, and if you are like me, you have a SSD for your OS and installed programs, and an HDD for storage. 4.3 million blocks is supposed to be around 70+ GB of files, which I certainly do not want on my SSD.

Etherum Wallet does not currently let you choose where to store these files, so by default they go to:

C:\Users\<username>\AppData\Roaming\Ethereum

So how can we move these files to our HDD?

Using Symbolic Links (Symlinks)!

Let’s do it!

I want to store all these files on my HDD at this folder path:

D:\Cryptocoins\Ethereum

Before I install Etherum Wallet, I should set up the symlink as so:

> Run CMD as an Administrator

mklink /j "C:\Users\<username>\AppData\Roaming\Ethereum" "D:\Cryptocoins\Ethereum"

If successful, you will get the following message:

Junction created for C:\Users\<username>\AppData\Roaming\Ethereum <<===>> D:\Cryptocoins\Ethereum

This will create a Directory Junction which basically makes the first folder path point to the second folder path. Then when I install and run Etherum Wallet, it will start to download all of the blocks into this alternate directory!

And in my HDD:

What if I migrate an existing installation?

Let’s say you already installed and downloaded the Ethereum Chain but you want to do this. Well that is also pretty easy. First copy all the contents from

C:\Users\<username>\AppData\Roaming\Ethereum

to your new location. It should be pretty large, so it may take a while. Be extra careful to make a backup of your keystore folder. Once the files have been copied over, you must delete the entire original Ethereum directory, including the Ethereum folder. Then you can run the same mklink in CMD as an Administrator.

mklink /j "C:\Users\<username>\AppData\Roaming\Ethereum" "D:\Cryptocoins\Ethereum"

If you forgot to delete the Ethereum folder, you will get this error:

Cannot create a file when that file already exists.

I hope this helps someone! It certainly helped me as I was getting started.

Adding AAD Service Principal to the Company Administrator Role using the AAD PowerShell Module

When creating a new Azure Active Directory application, developers may run into a a problem when calling the AAD Graph API where they lack the correct permissions to call the APIs they want when calling in the App Only Flow (Client Credentials Flow).

Is this message familiar to you?

"odata.error":{
    "code":"Authorization_RequestDenied",
    "message":{
        "lang":"en","value":"Insufficient privileges to complete the operation."
    }
}

The correct thing to do would be to try and investigate the permissions you have granted to your application, but there are some APIs which are not even supported through the permissions publicly exposed by the AAD Graph API. Maybe you just want to overcome this error for the time being and continue testing your end to end experience.

Using the AAD PowerShell Module, you can:

  • Give your application full access to the Graph API in the context of my tenant.

or

  • Grant your application permissions to my tenant which are not currently supported with the permissions exposed by the AAD Graph API.

“How?” you might ask. Well, you can elevate the level of access an Application has in your tenant by adding the service principal of that application to the Company Administrator Directory Role. This will give the Application the same level of permissions as the Company Administrator, who can do anything. You can follow these same instructions for any type of Directory Role depending on the level of access you want to give to this application.

Note that this will only affect the access your app has in your tenant.
Also you must already be a Company Administrator of the tenant to follow these instructions.

 

In order to make the change, you will need to install the Azure Active Directory PowerShell Module.

Once you have the module installed, authenticate to your tenant with your Administrator Account:

Connect-MSOLService

Then we need to get the Object ID of both the Service Principal we want to elevate, and the Company Administrator Role for your tenant.

Search for Service Principal by App ID GUID:

$sp = Get-MsolServicePrincipal -AppPrincipalId <App ID GUID>

Search for Directory Role by Name

$role = Get-MsolRole -RoleName "Company Administrator"

Now we can use the Add-MsolRoleMember command to add this role to the service principal.

Add-MsolRoleMember -RoleObjectId $role.ObjectId -RoleMemberType ServicePrincipal -RoleMemberObjectId $sp.ObjectId

To check everything is working, lets get back all the members of the Company Administrator role:

Get-MsolRoleMember -RoleObjectId $role.ObjectId

You should see your application in that list, where RoleMemberType is ServicePrincipal and DisplayName is the name of your application.

Now your application should be able to perform any Graph API calls that the Company Administrator could do, all without a user signed-in, using the Client Credential Flow.

Let me know if this helps!

Common Microsoft Resources in Azure Active Directory

I have seen a lot of StackOverflow posts trying to debug pretty basic errors when getting an access token to Microsoft Resources. Sometimes the issue is as simple as a typo in the “resource” value in the token request. When helping these users, I struggle to find public documentation which shows plainly the correct resource values for these different APIs!

That is going to change starting now. Here will be a list of the most popular Microsoft APIs exposed on Azure Active Directory, along with the basic information you may need to get an access token to those resources for PROD. (If you want the details for other Environments, let me know!)

Note: The Resource URI must match exactly what is written below, including any trailing ‘/’ or lack thereof.

 

Resource Name Resource URI Application ID
AAD Graph API https://graph.windows.net/ 00000002-0000-0000-c000-000000000000
Office 365 Exchange Online https://outlook-sdf.office.com/ 00000002-0000-0ff1-ce00-000000000000
Microsoft Graph https://graph.microsoft.com 00000003-0000-0000-c000-000000000000
Skype for Business Online https://api.skypeforbusiness.com/ 00000004-0000-0ff1-ce00-000000000000
Office 365 Yammer https://api.yammer.com/ 00000005-0000-0ff1-ce00-000000000000
OneNote https://onenote.com/ 2d4d3d8e-2be3-4bef-9f87-7875a61c29de
Windows Azure Service Management API https://management.core.windows.net/ 797f4846-ba00-4fd7-ba43-dac1f8f63013
Office 365 Management APIs https://manage.office.com c5393580-f805-4401-95e8-94b7a6ef2fc2
Microsoft Teams Services https://api.spaces.skype.com/ cc15fd57-2c6c-4117-a88c-83b1d56b4bbe
Azure Key Vault https://vault.azure.net cfa8b339-82a2-471a-a3c9-0fc0be7a4093

Who knows if this will actually end up helping anyone, but I hope it will!