Web-based NFT Wallet using Zilliqa Js API and ZilPay | Part-2

Vikram
Builders of Zilliqa
12 min readAug 25, 2021

In part one of the series, Web-Based NFT Portal using ZilliqaJs and ZilPay we deployed our NFT contract called StarNFTz and got ourselves familiar with Savant IDE and ViewBlock explorer.

In this 2nd part, we will focus on exploring the Zilliqa Js library using the ZilPay wallet and try out some cool Zilliqa-js javascript code in the browser console that we will require in the next parts of the series. So let’s start with the part-2 of our series 🙌🏻

Part 2— Exploring Zilliqa-Js using ZilPay Wallet.

Before starting let's go through some requirements that we may need in this part of the series.

System Requirement and Setup

For this part, we will mostly use the developer console provided by a browser and ZilPay wallet. Make sure you have a ZilPay wallet extension installed in any ZilPay supported browsers like Brave, Chrome, and Firefox.

Before starting, make a note that we will actually start building our wallet from the next part onwards, and this section is all about learning and getting familiar with the Zilliqa Js library using the developer console tool, So let’s get started now.

In this part, we will explore the Zilliqa Js library provided by the ZilPay wallet to us in the injected form in our browser.

A few of you may have a question, what is this injected library?

The injected library is a Js library that ZilPay provides to us as a javascript object whenever we load a page from some server. It is provided i.e injected as a part of a global window object by name zilPay and can be accessed using syntax window.zilPay or just zilPay

Once again, note that the app page needs to be loaded only from some internet or local server. ZilPay won’t inject it if the page is directly opened from the file system.

Some of you might be still confused 🤷‍♂️ but no worries, let's see this in action and you get more clarity on this. To get you familiar with the setup, follow the steps given below. Those familiar with using the dev console can skip it.

  • The first thing you need to do is; load any website/webpage in your browser, even this Medium article page that you are on should work fine.
  • Now open your browser dev tool and go to console. For Chrome/Brave browser, you can open the dev console by pressing opt+cmd+j on Mac or shift+ctrl+j on Windows/Linux devices or just right click your mouse and select inspect then go to console.
  • You will see a new dev tools window opened in your browser tab as below, now head over to the console section. In my case, I had opened a console on the IDE page itself. Now we are set to start exploring our Zilliqa Js library using the console.
Browsers Developer Console

Now from here onwards I have divided part 2 into various sections as follows:

  • The Zilliqa Js Library
  • Checking for ZilPay Wallet and Zilliqa Js Lib
  • Connect App to the Wallet
  • Checking Wallets network and account details
  • Tracking Wallet Changes
  • Querying Information From Blockchain
  • Querying Contract Details

In each of these sections, we will explore different aspects of the Zilliqa Js library in detail. I have referred all the API codes from the official Zilliqa Developer Portal, feel free to refer it as we go along. So let's get started with our first section.

2.1 The Zilliqa Js Lib

The Zilliqa Js is the Javascript library that allows us to interact with the ZilPay wallet and the Zilliqa blockchain. The library is divided into multiple modules, each independent and providing specific functionalities. Some of the modules are wallet, account, blockchain, contract, utils, etc.

More details on the library modules can be found here on Zilliqa Developer Portal and on GitHub, also the documentation for the ZilPay wallet can be found here.

2.2 Checking for ZilPay Wallet and Zilliqa Js Lib

To perform this check, type the following code in your console and then press enter.

if(window.zilPay){
console.log(“Zilpay present”)
}else{
console.log(“Cannot find Zilpay”)
}

If your console prints Zilpay present (see the image above) then it means that Zilpay is present and you can now access the Zilliqa Js library. If it prints Cannot find Zilpay then it means undefined i.e either your browser doesn’t have ZilPay installed or the wallet may be locked or the page may not be loaded from the server.

Here window.zilPay code means that you are trying to access the zilPay object which contains all the Zilliqa Js modules. The if-else statement print the message depending on whether window.zilPay is defined or undefined. If zilPay is present then it will hold an object which would mean a true value, else it will be afalse which means the window.zilPay is undefined.

2.3 Connect an App to the wallet

In the Wallet <> WebApp settings, there is something called Connections in a wallet that maintains the list of all apps connected/approved by the wallet owner to ensures restricted access of the wallet by the web app. You can check the list of all apps connected to your wallet by going to Setting -> Connections section of your ZilPay wallet.

To see this in action let's head to our console, type the following code and then press enter.

window.zilPay.wallet.connect().then(function(retVal){
console.log(retVal)
}
)
//Note: You can also use `await` which is more of a imperative code instead of `then` which is a callback mechanism.

This code is used to either check or establish a new connection of the current web app with the ZilPay wallet. If the App is connected then it will print a true message in the console. If the app is not connected then it will show a new ZilPay pop-up as shown below asking to establish and approve a connection.

Website Connection Request To Wallet

Now if you clickConnect then it will connect your wallet with the app and print a true message in the console. If you click cancel then it will print a false message in the console and no connection will be set up.

Let's see what is going on in this code. The window.zilPay.wallet.connect() provides the functionality for wallet connection and is responsible for opening the pop-up that we just saw. It returns something called as promise (more on which you can read here). The then method on the promise is used to handle the promise using a callback function(retVal) passed to it. In short, what this means is whenever we get a result response from the connect() call, this callback function is executed with the response result passed in as a function argument retVal.

2.4 Checking Wallets Current Network And Account Details

A wallet can be connected to different Zilliqa chains networks like Mainnet Testnet or Private. To check what chain our wallet is connected to, type the following code and then press enter.

window.zilPay.wallet.net
//net is a property and not function here.

It will print mainnet testnet or private depending on what network your wallet is connected to. Try changing the wallet network and try the code again, it will now give you the new networks’ name.

Now, let's check for current account details by typing the following code in your console and then press enter.

window.zilPay.wallet.defaultAccount
//defaultAccount is a property and not function
//Output:
{base16: "0x54962c592c329A6b58952315b4D67cD66eC39904", bech32: "zil12jtzckfvx2dxkky4yv2mf4nu6ehv8xgyf058yv"}

It will give you an object output as shown above. The result object has two key-value pairs with keys base16 and bech32 both of which represent the same address but in different encoding formats.

2.5 Tracking Wallet Changes

In the previous section, we saw how to access the current network and account details of a wallet which results in the detail at that particular time. As we know users' behavior may be dynamic, there may be a scenario where users change to some other network or account, but the context of the app will be still set in reference to the account and or network before, and may create malfunctioning in the app.

There should be a way such that the app needs will be notified of any such changes and it can then change its context and act accordingly. The wallet object provides us with a subscription method to do so using which we can observe network and account changes.

Let’s see how to observe a network change. Type the following code in your console, press enter and then try changing the network in your wallet.

window.zilPay.wallet.observableNetwork().subscribe(function (net) {
console.log("Network changed to " + net);
}
);
//Outputs: Network changed to <network_name_you_changed_to>

This code will log a message every time you change the network. Here observalbeNetwork() tells that we need to track network changes and the subscribe() method subscribes our callback function to be called whenever network change happens.

I got the following logs when I made the following sequence of network changes
mainnet->testnet->private->testnet

Tracking Wallet Change

Similarly, we can track account changes in our wallets using the observableAccount() method as shown in the following code:

window.zilPay.wallet.observableAccount().subscribe(function (newAcc)
{
console.log("Account changed to " +
newAcc.base16);
}
);
//newAcc is an Object of following pattern
{
base16: "0x54962c592c329A6b58952315b4D67cD66eC39904",
bech32: "zil12jtzckfvx2dxkky4yv2mf4nu6ehv8xgyf058yv"
}

This code will log a message Account changed to <Your Base16_Address> every time you change to some new account.

So far, we have explored only a few functionalities around the wallet module but there are many more which you can explore further in the library documentation.

Now let’s explore some codes of the blockchain and the contract modules using which we will query data from both the Zilliqa chain and Contracts.

2.6 Querying information from Blockchain

In this section, we will see two functionalities. First, to get the account balance and second, to get the Latest Transaction Block in details from the Zilliqa blockchain and log them to our dev console.

2.6.1 Get Account Balance

To get the Account balance, type the following code in the console and press Enter. Also note, we will query account balance from the blockchain and not from the wallet.

//get address from wallet and store it in `addr`
addr = window.zilPay.wallet.defaultAccount.bech32;
//Query blockchain for balance
window.zilPay.blockchain.getBalance(addr).then(function(resp){
console.log(resp);
}
)

Here we are getting the address from the wallet, storing it to a variable, and then querying balance from the blockchain by passing it to getBalance() method. If you have noticed, for querying blockchain we use the blockchain module of the library, and to query the wallet we use the wallet module.

After executing the above code and getting a response from the blockchain, you will get a log of a Javascript object as shown below.

Result Of Querying Account Balance From Blockchain

The response object has a result field with two properties, balance and nonce . balance is represented as Qa which is the smallest unit of the Zilliqa blockchain where 1ZIL = 10¹² Qa, thus in the above result we have ~3994.9358 Zil in our account. The nonce field is a counter in account for tracking the number of transactions done from that account, it also helps counter an attack called Replay Attack .

That was it for this sub-section, now let’s see the next sub-section on how to get details of the latest transaction block.

2.6.2 Get the latest Tx Block details

To get the latest Tx block details, type the following codes in your console and press enter.

window.zilPay.blockchain.getLatestTxBlock().then(
function(blockDetails){
console.log(blockDetails)
}
)

Here as you can observe, we are using the getLatestTxBlock() method of the blockchain module to query the latest transaction block details which will return a promise on-call and is handled using the then and callback mechanism.

This code will log all the block details of the latest transaction block fetched from the blockchain on whatever network you are on testnet, mainnet or private. The result should look something like the following and you can surely cross-check it with the data on the ViewBlock explorer.

Result Of Querying Latest Tx Block From Blockchain

As you can see, a lot of the latest Tx block details are logged in the console like hash, prev hash, timestamp, block number, DS block number, etc. which can be accessed and used like any other Javascript object.

There are a lot more codes to explore in the blockchain module which you can try out and analyze. Now, we will directly jump on to the next section where we will see how to read contracts states and data.

2.7 Querying Contract Details

In this section, we will see how to get a contract and read it using the contract library module. For reference, we will use the StarNFTz contract with the address 0x031f45f25df417a3d145dbc5d01e20153ac505ef that we had deployed in part-1 of our series.

The first thing we need to do is to create a contract object using the at(<contract-address>) method provided by the contract module. Type the following code in your console and press enter.

StarNFTzContract = window.zilPay.contracts.at("0x031f45f25df417a3d145dbc5d01e20153ac505ef");//It will return an initialised contract object as shown below in the screenshot below

The code will create a contract object called StarNFTzContract locally and initiate it with the address of our contract. If we log the contract object it prints a lot of details as shown below.

Create and Log of the Contract Object

Here the address field is defined but the other fields like code and init are still undefined. Also, if you inspect it further, you can see that StarNFTzContract object has a lot of properties and methods defined with it.

Here address code init are some properties and getInit getState getCode call are some methods. We will explore the call methods in detail in the latter part of this series. For now, we will see the getX() methods to query contract states and data.

2.7.1 getCode() and getInit() methods

Init and Code are the immutable data fields of the contract i.e they are read-only, cannot be changed, and are set while deploying the contract. getCode() and getInit() methods are used to get these details from the blockchain. Both these methods return a promise and also store the responses in their respective properties. Let's see how to get contract inits; type the following code in your console, and press enter.

StarNFTzContract.getInit().then(function(initData){
console.log("Init data received");
}
)
//It will give a similar output as shown in the below screeshot
Contract Inits and Code Log

As you can see above init property logs an object with all the init details like contract owner, block number, contract address, scilla version, contract name, and symbol.

Similarly, we can get the contract code using the getCode() method as shown above, where it will log an object containing a key-value pair with a key called code and its value will hold all the code as a string.

Now let’s see the last and an important method that we will use a lot in the next parts of the series.

2.7.2 getState() method

The State is the meat of the smart contracts, it stores mutable data and is only altered only via transition calls. In this part, we will only focus on reading the state of the contracts using the getState() method of the contract object which returns a promise.

Also, it doesn’t store this response state data in the contract object property as there is no such field defined for it. Though we can extend the object to store one, we will use a global variable to store our contract state.

To get the state of our contract, type the following code and press Enter. It will log the StarNFTz contract object in the console once the response is received from blockchain and will store the state in a global variable called StarNFTzContractState

var StarNFTzContractState;StarNFTzContract.getState().then(function(stateData){
console.log(stateData);
StartNFTzContractState = stateData;
}
)

It will give the following output in the console:

NFT Contract State Log

As we can see in the blue highlighted box, all the state details of our StarNFTz contract are logged. State object has all the details like token owners, token URI, total NFT supply, etc to build our NFT gallery.

As you can see, we have token owner mapping token ids to owner address and also we have token URI mapping token ids to a URI path. Now we can loop through these mappings and dynamically create an NFT image gallery, doesn’t that sound cool? Surely it does, but it would be cooler to actually build it which we will do in the next part of this series.

Zilliqans, that was it for Part 2 of this series, hope you all liked it. We explored a lot of new concepts in this part and would recommend you all to explore Zilliqa Js more and try out some more codes before jumping on to the next parts.

In the next part, we will build a gallery for our NFT contract using the Zilliqa Js library and simple web tools like HTML, CSS, and Javascript. Till then, stay tuned and stay safe 😃

If you have any feedback, suggestions, or inputs feel free to write me on Twitter @NakamotoVikram

--

--