Last Updated: 2021-08-18
Hic Et Nunc (HEN) is an experimental non-fungible token (NFT) marketplace covering a wide range of visual art, interactive art, music, and animations from a diverse group of artists worldwide.
HEN has a diverse community of well-known and less-known artists with a wide range of backgrounds. HEN allows artists to sell their artwork for much lower fees and with significantly less environmental impact than other NFT marketplaces. On both Twitter and Discord, you will find artists that support each other by buying and promoting each other's work.
HEN is what is referred to as a DApp (decentralized application) and is built on the Tezos blockchain. HEN utilizes smart contracts to manage the minting, selling, and buying processes to ensure the artist is paid for each sale and receives royalties for secondary sales. The smart contracts store information about each NFT in the Tezos blockchain.
A unique aspect of HEN as an NFT marketplace is that it is open-sourced on GitHub. The code provides an insight into the workings of a marketplace that isn't possible with other closed source platforms.
There is also a growing number of tools made by the HEN community, many open-sourced.
In this codelab, you will build a web app that displays an image from the HEN marketplace. This web app will be a much simpler version of what the HEN marketplace website provides to view the available artworks for sale.
This codelab focuses on web apps. Non-relevant concepts and code blocks are glossed over and are provided for you to simply copy and paste.
Familiarity with JavaScript (ES6) is strongly recommended to help you understand the code used in this codelab.
In this codelab, you build the app step-by-step from an incomplete version. If you prefer, you can also get the completed app from the GitHub repository.
In this section, you will set up your development environment. You will use a simple HTTP web server on your local machine using Node.js for doing development. The webserver runs on the http-server
npm package, a simple zero-configuration http server for serving static files to the browser. This web server starts from the command line.
This codelab uses the node package manager (npm) to install various packages. Make sure to install npm, which typically comes with Node.js.
If you haven't installed Node yet, download the latest stable release of Node.js and install it using all the default options.
Install the http-server
globally on your machine using the npm command-line tool. This will allow you to run a web server from anywhere on your computer.
Open a terminal window and enter the following npm
command:
npm install -g http-server
In this section, you clone the files you need for this codelab.
Open a terminal and change to a folder where you usually store coding projects. If you don't have one, change it to your home folder. Unzip the downloaded zip file into your coding folder.
Open the start
folder. This folder contains the following essential files that you'll be working with:
index.html
: The starting HTML file for the web app.package.json
: The npm
configuration file.Let npm
download any dependencies for the project by running this command:
npm install
Change to the start folder containing in the command line window, e.g.:
cd \codelab1\start
Start the server with this command:
http-server
You should see something like the following:
Starting up http-server, serving ./
Available on:
http://192.168.86.36:8080
http://127.0.0.1:8080
Hit CTRL-C to stop the server
Open a browser tab to http://localhost:8000. You should see a web page with the message: "Ready for the codelab!"
.
The HTTP server console should display something like this:
[2021-08-16T15:05:20.493Z] "GET /" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
(node:26604) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
(Use `node --trace-deprecation ...` to show where the warning was created)
In this section, you will create a query for the HEN marketplace data. You send a query to hicdex, a Tezos indexer focused on indexing HENs smart contracts activity.
The indexed data is made available by exposing a public GraphQL endpoint. You can interactively create GraphQL queries for hicdex using its GraphQL explorer.
You will use hicdex to query for an NFT minted on HEN and then display the image for that NFT.
You will use the following hicdex queries:
hic_et_nunc_swap
: Get the token ID of the NFT on HEN.hic_et_nunc_token
: Using the token ID, get the associated token information about the artwork.Here is the query syntax you will use to get the NFT token ID:
query MyQuery {
hic_et_nunc_swap(limit: 1,
where: {token: {mime: {_like: "image/%"}},
contract_version: {_eq: "2"}}, order_by: {token_id: desc}) {
token_id
}
}
This query asks hicdex to return the token ID (token_id
) of a single (limit: 1
) token:
hic_et_nunc_swap)
,"image/%")
,contract_version
) is 2 (the latest contract version for HEN),desc
) order by the token ID (i.e., latest token first).The result of this query will return the token ID as JSON:
{
"data": {
"hic_et_nunc_swap": [
{
"token_id": 1
}
]
}
}
Here is the query syntax you will use to get the token information:
query MyQuery($token_id: bigint) {
hic_et_nunc_token(where: {id: {_eq: $token_id}}) {
artifact_uri
}
}
This query asks hicdex to return the token image URL (artifact_uri
) for an NFT with an ID that equals (_eq
) the given token ID (token_id
).
The result of this query will return the token ID as JSON:
{
"data": {
"hic_et_nunc_token": [
{
"artifact_uri": "ipfs://..."
}
]
}
}
In this section, you will learn how to invoke the hicdex public API, which allows developers to invoke queries against the indexed HEN data it maintains.
To query hicdex, you have to use its GraphQL endpoint at:
https://api.hicdex.com/v1/graphql
This involves making an HTTP POST request to that URL with a payload that consists of these values:
query
- the GraphQL syntax for hicdex queries.variables
- list of variable values for the query in JSON format.operationName
- the name of the query that is invoked (for example, in the query in the previous section, it is MyQuery
)These three values need to pass in the body of the request in JSON format:
{
query: "query MyQuery {...}",
variables: {"name": value},
operationName: "MyQuery"
}
For the query to get the NFT token ID, there aren't any parameter values to be passed along in the request, so the variables
value will be the JSON empty value of {}
.
To invoke the endpoint using JavaScript, you will use the Fetch API, which allows you to make HTTP requests.
Add the following JavaScript code between the script
tags in the HTML:
const data = {
query: `query MyQuery {
hic_et_nunc_swap(limit: 1,
where: {token: {mime: {_like: "image/%"}},
contract_version: {_eq: "2"}}, order_by: {token_id: desc}) {
token_id
}
}`,
variables: {},
operationName: "MyQuery"
}
fetch("https://api.hicdex.com/v1/graphql", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
console.log('Success: ', data)
})
.catch((error) => {
console.error('Error: ', error)
})
Save the index.html file and force a reload of the index.html file in your browser (in Chrome, use Ctrl+F5).
DevTools provides a quick, easy way to check your index.html file logging. Open up DevTools by using the Ctrl+Shift+I keyboard shortcut. Click on the Console tab to see the logging output from the JavaScript code.
You should see something like this for the console output:
The result of this query returns the token ID as JSON:
{
"data": {
"hic_et_nunc_swap": [
{
"token_id": 200165
}
]
}
}
Adding logging statements to your JavaScript code is an easy way to debug the logic and confirm that the data is in the format you expect.
Since we will be doing the same kind of fetch operations to query hicdex, it makes sense to create a reusable function instead of adding more fetch calls. Also, instead of using the Promise notation (then
, catch
), which can make the code deeply nested, we will make the code read more synchronously by using async
functions.
Remove the current JavaScript code between the script
tags and replace it with:
async function fetchHicdex(query, variables, operationName) {
const result = await fetch(
"https://api.hicdex.com/v1/graphql", {
method: "POST",
body: JSON.stringify({
query: query,
variables: variables,
operationName: operationName
})
}
)
const json = await result.json()
console.log(JSON.stringify(json))
return json
}
async function querySwap() {
const {
errors,
data
} = await fetchHicdex(`query MyQuery {
hic_et_nunc_swap(limit: 1,
where: {token: {mime: {_like: "image/%"}},
contract_version: {_eq: "2"}},
order_by: {token_id: desc}) {
token_id
}
}`, {}, "MyQuery")
if (errors) {
console.error(errors)
return false
}
const result = data.hic_et_nunc_swap
if (result.length == 0) {
return false
}
console.log(result)
return result
}
querySwap()
This code logically does the same as the previous code, but sets up the code to be more reusable and readable as we add new JavaScript logic. There is also better error handling by explicitly checking for hicdex errors and verifying that we got the results we expected. The output in the DevTools console should be similar to before.
In this section, you will query hicdex for the information associated with a particular token ID.
Replace the previous querySwap()
call (not the function declaration) with the following JavaScript code:
async function queryTokenInfo(token_id) {
const {
errors,
data
} = await fetchHicdex(`query MyQuery($token_id: bigint) {
hic_et_nunc_token(where: {id: {_eq: $token_id}}) {
artifact_uri
}
}`, {
token_id: token_id
}, "MyQuery")
if (errors) {
console.error(errors)
return false
}
const result = data.hic_et_nunc_token
if (result.length == 0) {
return false
}
console.log(result)
return result
}
async function displayNft() {
const swap = await querySwap()
if (swap) {
const info = await queryTokenInfo(swap[0].token_id)
}
}
displayNft()
Save the index.html file and force a reload of the index.html file in your browser.
In DevTools, you will see the result of this query returns the token artifact URL as JSON:
{
"data": {
"hic_et_nunc_token": [
{
"artifact_uri":
"ipfs://QmS1r91dZadi4XQ6TuFcUVTUBnhphS7B428YdfETfjs6yL"
}
]
}
}
Now that you have the URL for the image of a HEN NFT, the next step is to display that image using HTML.
In this section, you will use the artifact URL for the token to display the image of an NFT in HTML.
Add the following CSS styling inside the head
tag:
<style>
body,
html {
margin: 0;
padding: 0;
overflow: hidden;
}
img {
width: 100vw;
height: 100vh;
object-fit: contain;
}
</style>
This CSS styling will display an image along the entire width of the browser window.
To display the image we can use the img
tag. Change the contents of the root div
tag to:
<div id="root">
<img id="image" />
</div>
The img
tag has an id of "image"
which we can use to reference it in JavaScript code.
The "artifact_uri"
provided by the hicdex query result starts with the IPFS protocol:
ipfs://QmZSXELDJEhEJ6BsVdPQozetm34LDWTApyW6wQu1zv2LUg
Browsers like Chrome cannot directly display images with this protocol. To display an image with the img
tag, you need an HTTP URL. An IPFS HTTP gateway such as ipfs.io allows browsers to access files stored on the IPFS network using the HTTP protocol.
To convert a URL with the IPFS protocol to the HTTP protocol, you must append the content identifier (CID) to the gateway address. The CID is the large alphanumeric ID after the ipfs://
protocol.
To convert the IPFS address to an HTTP address, add the following JavaScript:
function ipfsToHttp(url) {
return url.replace('ipfs://', 'https://ipfs.io/ipfs/')
}
This code updates the URL string value by replacing the IPFS protocol prefix with the HTTP gateway address.
Replace the existing displayNft
function declaration with the following code to display the NFT image:
async function displayNft() {
const swap = await querySwap()
if (swap) {
const info = await queryTokenInfo(swap[0].token_id)
if (info) {
image.src = ipfsToHttp(info[0].artifact_uri)
}
}
}
displayNft()
This code converts the artifact_uri
value to an HTTP gateway URL and then updates the img
tag src
value so that the browser will display the image.
The code for this web app is quite simple. Various aspects could be improved, for example:
Congratulations, you've successfully built your first HEN web app!!
You invoked the hicdex API to query for NFT token information and then used that to display the image of a HEN NFT. You learned how to use DevTools to view the logs of your web app.
You now know some of the basics of how the HEN website works.