ajcwebdev
Blog post cover art for A First Look at Dash

A First Look at Dash

Published:

Dash is a cryptocurrency launched in 2014 that aims to be a convenient, fast, and private digital cash platform that is suitable for everyday transactions.

Outline

Dash Platform Overview

Dash is a digital cryptocurrency that was launched in 2014. Originally called XCoin (XCO), it was renamed Darkcoin and then finally rebranded as Dash in 2015. “Dash” is a portmanteau of “Digital Cash” and was created as a fork of Bitcoin. Despite its origins, today Dash differs significantly from Bitcoin by aiming to be a convenient, fast, and private digital cash platform that is suitable for everyday transactions. This goal is reflected in its design features which include:

  • PrivateSend: This feature ensures user privacy by mixing transactions together, making them untraceable to individual users.
  • InstantSend: Dash’s InstantSend feature enables near-instant transaction confirmations that are faster than Bitcoin’s.
  • Masternodes: Dash’s network includes masternodes (or full nodes) which power its unique features like InstantSend and PrivateSend, as well as its governance system.
  • Decentralized Autonomous Organization: Dash operates as a DAO, meaning it is a transparent, member-controlled organization free from central government influence.
  • Block Reward Allocation: Dash’s block reward is split between miners (45%), masternodes (45%), and a development fund (10%), ensuring ongoing platform maintenance and development.

In 2019, an MVP of the Dash Platform (originally codenamed “Evonet”) was launched. The Dash Platform is a technology stack for building decentralized applications (dApps) on the Dash network. It represents a shift away from the original, transaction-focused blockchain systems inspired by Bitcoin by aiming to make Dash more like newer, application-focused blockchains such as Ethereum and Solana.

Key features of the platform include:

  • Dash Drive: A decentralized API that lets users store and interact with data on the Dash network, similar to a cloud database service.
  • Decentralized API (DAPI): Allows developers secure, decentralized access to full node capabilities without needing to host one.
  • Usernames via Dash Platform Name Service (DPNS): Enables the creation of memorable usernames to replace complex cryptographic addresses.
  • Platform Chain: A separate chain for storing platform data, secured by the masternodes of the main Dash network.
  • Dash Libraries: A collection of integrated open source libraries for developing on the Dash Platform.

The Dash roadmap is always publicly viewable so users and developers can see what is being worked on for the next year or so development. Right now the upcoming network implementations schedule for 2024 and beyond include the following:

  • Dash Platform v1.0 (ROLL OUT) begins the roll out of the platform on Mainnet.
    • The release will emphasize written documentation, tutorials, and Dash Improvement Proposals (DIPs).
    • v1.0 ACTIVATION will signal the official activation of the protocol and triggers after a specific number of masternode owners upgrade.
    • The DashPay Launch will complete the v1.0 release and enable creating on-chain usernames for the official DashPay mobile app.
  • Dash Platform v2.0 plans to build in support for both of the following:
    • Fungible tokens to mint specific tokens.
    • Non-fungible tokens for storing NFT data on chain.
  • Dash Platform v3.0 will add a Virtual Machine for Smart Contracts to allow on-chain computation.
  • Dash Platform v4.0 implements the Inter-Blockchain Communication Protocol (IBC) to enable permissionless, cross-chain applications.
    • As of April 2024, this is the last scheduled release currently on the roadmap

Setup and Configure Node Project

Terminal window
mkdir dash-examples
cd dash-examples
npm init -y
npm pkg set type="module"
npm i dash@1.0-dev
echo '.DS_Store\nnode_modules\n.env\ndist' > .gitignore

We’ll create each script file individually throughout the tutorial but for the sake of simplifying your life while following along with this tutorial, I’d recommend adding all of the Node scripts that will be implemented by the end of the tutorial.

{
"name": "dash-examples",
"description": "An example application using the Dash JavaScript SDK",
"keywords": [ "Dash", "JavaScript" ],
"author": "Anthony Campolo",
"license": "MIT",
"type": "module",
"dependencies": {
"dash": "^4.0.0-dev.10"
},
"scripts": {
"getBlockMethods": "node --env-file=.env scripts/getBlockMethods",
"createWallet": "node --env-file=.env scripts/createWallet",
"createIdentity": "node --env-file=.env scripts/createIdentity",
"retrieveIdentities": "node --env-file=.env scripts/retrieveIdentities",
"topupIdentities": "node --env-file=.env scripts/topupIdentities",
"registerName": "node --env-file=.env scripts/registerName",
"retrieveName": "node --env-file=.env scripts/retrieveName",
"registerContract": "node --env-file=.env scripts/registerContract",
"retrieveContract": "node --env-file=.env scripts/retrieveContract",
"updateContract": "node --env-file=.env scripts/updateContract",
"submitNoteDocument": "node --env-file=.env scripts/submitNoteDocument",
"getDocuments": "node --env-file=.env scripts/getDocuments",
"updateNoteDocument": "node --env-file=.env scripts/updateNoteDocument",
"deleteNoteDocument": "node --env-file=.env scripts/deleteNoteDocument",
"express": "node --env-file=.env --watch api/server"
}
}

Initialize Dash Client and Query Blocks

Create a scripts directory for our Node scripts and an api directory with a file called client.js for initializing Dash.Client. The network will be set to testnet via the NETWORK environment variable in .env.

Terminal window
mkdir api scripts
echo > api/client.js
echo 'NETWORK="testnet"' > .env

Import Dash from dash, pass the project’s network and wallet configuration through Dash’s Client constructor, and export client.

api/client.js
import Dash from "dash"
const { NETWORK } = process.env
export const client = new Dash.Client({
network: NETWORK,
wallet: {
mnemonic: null,
offlineMode: true,
},
})
  • Because we haven’t created a wallet yet, mnemonic is set to null to indicate we want a new wallet to be generated. To get a new address for an existing wallet replace null with an existing wallet mnemonic.
  • offlineMode is set to true, indicating we don’t want to sync the chain. This can only be used when the mnemonic is set to null.

Create a file called getBlockMethods.js which will be used to query block data.

Terminal window
echo > scripts/getBlockMethods.js
  • getBestBlockHash returns the block hash of the chaintip.
  • getBlockHash returns the block hash of a given height.
    • In blockchain terminology, “height” refers to the position of a block in the chain. The first block ever mined (also known as the genesis block) typically has a height of 0.
    • Each subsequent block that’s added to the chain increases the height by one so the height of a block also represents the total number of blocks that precede it in the chain.
  • getBlockByHeight fetches a specific block by its height.
    • Unlike getBlockHash, it returns a bufferized block instead of the corresponding block hash.
scripts/getBlockMethods.js
import { client } from '../api/client.js'
async function dapiClientMethods() {
try {
const dapiClient = client.getDAPIClient().core
console.log("\ngetBlockHash(1):", await dapiClient.getBlockHash(1))
console.log("\ngetBestBlockHash():", await dapiClient.getBestBlockHash())
console.log("\ngetBlockByHeight():", await dapiClient.getBlockByHeight(1))
} catch (error) {
console.error('Something went wrong:\n', error)
} finally {
client.disconnect()
}
}
dapiClientMethods()

Run the getBlockMethods script:

Terminal window
npm run getBlockMethods

You’ll receive the following output:

getBlockByHeight(): <Buffer 02 00 00 00 2c bc f8 3b 62 91 3d 56 f6 05 c0 e5 81 a4 88 72 83 94 28 c9 2e 5e b7 6c d7 ad 94 bc af 0b 00 00 7f 11 dc ce 14 07 55 20 e8 f7 4c c4 dd f0 ... 136 more bytes>
getBlockHash(1): 0000047d24635e347be3aaaeb66c26be94901a2f962feccd4f95090191f208c1
getBestBlockHash(): 000000ec93f8559ca1bd9f5391519457d596a2e806bc18934b4208a67d7e8613
  • getBlockByHeight() returned a <Buffer> object, which is a Node.js type used to efficiently represent a sequence of bytes. Since blockchain data is binary, it’s represented as a buffer when accessed programmatically.

  • getBlockHash(1) returns the hash of the block at height 1 as a hexadecimal string. Block hashes are unique identifiers for blocks and are derived from the block header information, including the previous block’s hash, a timestamp, and a nonce among other data. This particular hash identifies the first block after the genesis block in the Dash blockchain.

  • getBestBlockHash() returns the hash of the latest block in the longest chain, which is considered the current state of the blockchain and is the most recently confirmed block at the time of the query.

Create Wallet and Identity

Create a file called createWallet.js.

Terminal window
echo > scripts/createWallet.js

We’ll use three functions to create a wallet:

  • getWalletAccount() to get our wallet
  • exportWallet() to export the 12 word mnemonic phrase
  • getUnusedAddress() to create a new address
scripts/createWallet.js
import { client } from '../api/client.js'
async function createWallet() {
try {
const walletAccount = await client.getWalletAccount()
const mnemonic = client.wallet.exportWallet()
const { address } = walletAccount.getUnusedAddress()
console.log("WALLET_ADDRESS=" + `"${address}"`)
console.log("MNEMONIC=" + `"${mnemonic}"`)
} catch (error) {
console.error('Something went wrong:\n', error)
} finally {
client.disconnect()
}
}
createWallet()

Run the createWallet script.

Terminal window
npm run createWallet

The output will include our two environment variables:

WALLET_ADDRESS="yfvkghuK1fbDc7GBeadfMa47d9WaBpLxij"
MNEMONIC="motion certain ritual what parrot security leisure mountain cigar flight range omit"

Copy these and place them in your .env. We’ll do the same throughout the rest of this tutorial.

Add Funds to Wallet with Testnet Faucet

Send test funds to the “unused address” from the console output using Dash’s testnet faucet. Wait for the funds to be confirmed before trying to use them, it may take a few minutes. You can check the status of confirmations with the Dash block explorer.

Search for your wallet address (yfvkghuK1fbDc7GBeadfMa47d9WaBpLxij in my case) to see your balance and list of transactions:

01 - Viewing new Dash wallet address on testnet block explorer

Click on the transaction link (9ca05a57d2f8e55068a5c8be4453d3a84aa852304d1aa3d32d92b9b5afe32261 in my case) to view information on the transaction itself.

02 - Viewing new Dash faucet transaction on testnet block explorer

You can also click on the plus symbol (+) next to the transaction link for more information related to the transaction confirmation.

03 - Viewing new transaction confirmation info on testnet block explorer

Register and Retrieve Identity

Modify the client again and include your wallet’s MNEMONIC seed phrase saved in .env.

api/client.js
import Dash from "dash"
const { NETWORK, MNEMONIC } = process.env
export const client = new Dash.Client({
network: NETWORK,
wallet: {
mnemonic: MNEMONIC,
unsafeOptions: {
skipSynchronizationBeforeHeight: 990000,
},
},
})

Create a file called createIdentity.js.

Terminal window
echo > scripts/createIdentity.js

To create an identity, we’ll run the identities.register() function.

scripts/createIdentity.js
import { client } from '../api/client.js'
async function createIdentity() {
try {
const identity = await client.platform.identities.register()
console.log("IDENTITY_ID=" + `"${identity.toJSON().id}"`)
console.log(`\nView on platform block explorer: https://platform-explorer.com/identity/${identity.toJSON().id}\n`)
} catch (error) {
console.error('Something went wrong:\n', error)
} finally {
client.disconnect()
}
}
createIdentity()

Run the createIdentity script.

Terminal window
npm run createIdentity

Output:

IDENTITY_ID="8sLPonoGyxQ4h9yBKQainVPLc3QDGKiGjjHHor7nUbTf"

Earlier, we saw how to view our transactions on the Dash block explorer. For operations performed on Dash Platform, there is a separate explorer at platform-explorer.com.

  • Open the Identities tab to see your ID on the list.
  • Alternatively, createIdentity appends the ID to the URL https://platform-explorer.com/identity/ and outputs the link to your terminal for convenience.

04-platform-explorer-identity-endpoint

Create a file called retrieveIdentities.js.

Terminal window
echo > scripts/retrieveIdentities.js

getIdentityIds() with return your identity ID’s which can be passed to identities.get().

scripts/retrieveIdentities.js
import { client } from '../api/client.js'
async function retrieveIdentities() {
try {
const walletAccount = await client.getWalletAccount()
const identityIds = walletAccount.identities.getIdentityIds()
console.log("\nRetrieved Identity IDs:\n" + JSON.stringify(identityIds, null, 2))
for (const id of identityIds) {
const identity = await client.platform.identities.get(id)
console.log(`\nIdentity ID: ${id}`)
console.log(` - Balance: ${identity.balance}`)
}
} catch (error) {
console.error('Something went wrong:\n', error)
} finally {
client.disconnect()
}
}
retrieveIdentities()

Run the retrieveIdentities script:

Terminal window
npm run retrieveIdentities

When an Identity is created, a special transaction transforms Dash into credits which are used to interact with Dash Platform. 1 DASH is equal to 100,000,000 Duffs (Dash’s version of the Satoshi) and 100 million Duffs is equal to 100 billion credits. Since interacting with Dash Platform applications decreases your credit balance, at a certain point you’ll need to topup the balance by converting some Dash to credits.

Create a file called topupIdentities.js.

Terminal window
echo > scripts/topupIdentities.js

getIdentityIds() will be used again and the ID’s will be passed to identities.topUp().

scripts/topupIdentities.js
import { client } from '../api/client.js'
async function topupIdentities() {
try {
const walletAccount = await client.getWalletAccount()
const identityIds = walletAccount.identities.getIdentityIds()
for (const id of identityIds) {
await client.platform.identities.topUp(id, 100000000)
const identity = await client.platform.identities.get(id)
console.log(`IDENTITY_CREDIT_BALANCE for ID ${id}: ${identity.balance}`)
}
} catch (error) {
console.error('Something went wrong:\n', error)
} finally {
client.disconnect()
}
}
topupIdentities()

Run the topupIdentities script:

Terminal window
npm run topupIdentities

Register and Retrieve Name

Create a file called registerName.js.

Terminal window
echo > scripts/registerName.js

Create a LABEL in .env with your desired name. I will be using ajcwebdev.

Terminal window
echo '\nLABEL="ajcwebdev"' >> .env
scripts/registerName.js
import { client } from '../api/client.js'
const { IDENTITY_ID, LABEL } = process.env
async function registerName() {
try {
const identity = await client.platform.identities.get(IDENTITY_ID)
const dashUniqueIdentityId = await identity.getId()
const nameRegistration = await client.platform.names.register(
`${LABEL}.dash`, { dashUniqueIdentityId }, identity
)
console.log("LABEL=" + JSON.stringify(nameRegistration.toJSON().label))
console.log(`\nView on block explorer: https://platform-explorer.com/document/${nameRegistration.toJSON().$id}\n`)
} catch (error) {
console.error("Something went wrong:\n", error)
} finally {
client.disconnect()
}
}
registerName()

Run the registerName script:

Terminal window
npm run registerName

05-platform-explorer-document-endpoint

Create a file called retrieveName.js.

Terminal window
echo > scripts/retrieveName.js

Pass your name to platform.names.resolve().

scripts/retrieveName.js
import { client } from '../api/client.js'
const { LABEL } = process.env
async function retrieveName() {
try {
const extendedDoc = await client.platform.names.resolve(`${LABEL}.dash`)
const name = JSON.parse(JSON.stringify(extendedDoc))
console.log(`\nResolved name object:\n\n`, name)
console.log(`\nView on block explorer: https://platform-explorer.com/document/${name.$id}\n`)
} catch (error) {
console.error('Something went wrong:\n', error)
} finally {
client.disconnect()
}
}
retrieveName()

Run the retrieveName script:

Terminal window
npm run retrieveName

Data Contracts

A Data Contract on Dash Platform serves as a blueprint for the structure of data that an application intends to store on the decentralized network. It defines the schema of documents (data records) with JSON Schema.

  • Contracts enable the platform to validate data against these schemas to ensure consistency and integrity.
  • They are crucial for dApps and provide a structured and predictable way to interact with the Dash blockchain.
  • Data Contracts facilitate data storage, retrieval, and manipulation in a trustless environment.

Register, Retrieve, and Update Contract

Create a file called registerContract.js.

Terminal window
echo > scripts/registerContract.js

contracts.create() will take your identity and a spec for the contract. In this case the contract will be a simple string message.

scripts/registerContract.js
import { client } from '../api/client.js'
const { IDENTITY_ID } = process.env
const registerContract = async () => {
try {
const identity = await client.platform.identities.get(IDENTITY_ID)
const contractDocuments = {
note: {
type: 'object',
properties: { message: { type: 'string', position: 0 } },
additionalProperties: false
}
}
const contract = await client.platform.contracts.create(contractDocuments, identity)
console.log("\nCONTRACT_ID=" + `"${contract.toJSON().id}"`)
await client.platform.contracts.publish(contract, identity)
console.log('\nContract registered:\n\n', contract.toJSON())
console.log(`\nView on platform block explorer:\n\nhttps://platform-explorer.com/dataContract/${contract.toJSON().id}\n`)
} catch (e) {
console.error('Something went wrong:\n', e)
} finally {
client.disconnect()
}
}
registerContract()

Run the registerContract script:

Terminal window
npm run registerContract

Create a file called retrieveContract.js.

Terminal window
echo > scripts/retrieveContract.js

Pass your contract ID to contracts.get().

scripts/retrieveContract.js
import { client } from '../api/client.js'
const { CONTRACT_ID } = process.env
const retrieveContract = async () => {
try {
const contract = await client.platform.contracts.get(CONTRACT_ID)
console.dir(contract.toJSON(), { depth: 5 })
console.log(`\nView on platform block explorer:\n\nhttps://platform-explorer.com/dataContract/${contract.toJSON().id}\n`)
} catch (e) {
console.error('Something went wrong:\n', e)
} finally {
client.disconnect()
}
}
retrieveContract()

Run the retrieveContract script.

Terminal window
npm run retrieveContract

Create a file called updateContract.js.

Terminal window
echo > scripts/updateContract.js

Use your identity ID and contract ID along with setDocumentSchema() and contracts.update().

scripts/updateContract.js
import { client } from '../api/client.js'
const { IDENTITY_ID, CONTRACT_ID } = process.env
const updateContract = async () => {
try {
const identity = await client.platform.identities.get(IDENTITY_ID)
const existingDataContract = await client.platform.contracts.get(CONTRACT_ID)
const documentSchema = existingDataContract.getDocumentSchema('note')
documentSchema.properties.author = {
type: 'string',
position: 1
}
existingDataContract.setDocumentSchema('note', documentSchema)
await client.platform.contracts.update(existingDataContract, identity)
console.log('\nContract updated:\n\n', existingDataContract.toJSON())
} catch (e) {
console.error('Something went wrong:\n', e)
} finally {
client.disconnect()
}
}
updateContract()

Run the updateContract script.

Terminal window
npm run updateContract

Add an apps object to the client options and pass the contract ID to enable <contract name>.<contract document> syntax while accessing contract documents (for example, tutorialContract.note).

api/client.js
import Dash from "dash"
const { NETWORK, MNEMONIC, CONTRACT_ID } = process.env
export const client = new Dash.Client({
network: NETWORK,
wallet: {
mnemonic: MNEMONIC,
unsafeOptions: {
skipSynchronizationBeforeHeight: 990000,
},
},
apps: {
tutorialContract: {
contractId: CONTRACT_ID,
},
},
})

Submit and Retrieve Documents

Create a file called submitNoteDocument.js.

Terminal window
echo > scripts/submitNoteDocument.js
scripts/submitNoteDocument.js
import { client } from '../api/client.js'
const { IDENTITY_ID } = process.env
const submitNoteDocument = async () => {
try {
const identity = await client.platform.identities.get(IDENTITY_ID)
const noteDocument = await client.platform.documents.create(
'tutorialContract.note',
identity,
{ message: `Hello from ajcwebdev @ ${new Date().toUTCString()}` },
)
await client.platform.documents.broadcast({
create: [noteDocument],
replace: [],
delete: [],
}, identity)
console.log(`DOCUMENT_ID="${noteDocument.toJSON().$id}"`)
console.log(noteDocument.toJSON())
} catch (e) {
console.error('Something went wrong:\n', e)
} finally {
client.disconnect()
}
}
submitNoteDocument()

Run the submitNoteDocument script.

Terminal window
npm run submitNoteDocument

Create a file called getDocuments.js.

Terminal window
echo > scripts/getDocuments.js
scripts/getDocuments.js
import { client } from '../api/client.js'
const getDocuments = async () => {
try {
const documents = await client.platform.documents.get(
'tutorialContract.note',
{ limit: 5 }
)
console.log('\nLast 5 messages:\n')
documents.forEach(n => console.log(n.toJSON().message))
} catch (e) {
console.error('Something went wrong:\n', e)
} finally {
client.disconnect()
}
}
getDocuments()

Run the getDocuments script:

Terminal window
npm run getDocuments

Output:

Hello from ajcwebdev @ Tue, 09 Apr 2024 08:11:25 GMT

Update and Delete Documents

Create a file called updateNoteDocument.js.

Terminal window
echo > scripts/updateNoteDocument.js
scripts/updateNoteDocument.js
import { client } from '../api/client.js'
const { IDENTITY_ID, DOCUMENT_ID } = process.env
const updateNoteDocument = async () => {
try {
const identity = await client.platform.identities.get(IDENTITY_ID)
const [document] = await client.platform.documents.get(
'tutorialContract.note',
{ where: [['$id', '==', DOCUMENT_ID]] },
)
document.set(
'message',
`Hello from ajcwebdev again @ ${new Date().toUTCString()}`
)
await client.platform.documents.broadcast({ replace: [document] }, identity)
console.log('\nMessage: ', document.toJSON().message)
console.log('\nDocument updated:\n\n', document.toJSON())
} catch (e) {
console.error('Something went wrong:\n', e)
} finally {
client.disconnect()
}
}
updateNoteDocument()

Run the updateNoteDocument script:

Terminal window
npm run updateNoteDocument

Now that we can create, read, and update our notes, all we have left to do is delete our notes. Create a file called deleteNoteDocument.js.

Terminal window
echo > scripts/deleteNoteDocument.js
scripts/deleteNoteDocument.js
import { client } from '../api/client.js'
const { IDENTITY_ID, DOCUMENT_ID } = process.env
const deleteNoteDocument = async () => {
try {
const identity = await client.platform.identities.get(IDENTITY_ID)
const [document] = await client.platform.documents.get(
'tutorialContract.note',
{ where: [['$id', '==', DOCUMENT_ID]] },
)
await client.platform.documents.broadcast({ delete: [document] }, identity)
console.log('Document deleted:\n', document.toJSON())
} catch (e) {
console.error('Something went wrong:\n', e)
} finally {
client.disconnect()
}
}
deleteNoteDocument()

Run the deleteNoteDocument script:

Terminal window
npm run deleteNoteDocument

Setup Backend Server with Express

We’ve now learned how to run individual scripts to perform all the main functionality on the Dash Platform. Like any JavaScript library, we can extend this functionality with a backend and frontend. Let’s create an Express server that will return information on a given identity name.

Terminal window
npm i express cors
echo > api/server.js

Create a /name endpoint that will take an identity name:

api/server.js
import express from 'express'
import cors from 'cors'
import { client } from './client.js'
const app = express()
app.use(cors())
app.get('/name/:identityName', async (req, res) => {
try {
const name = req.params.identityName
const result = await client.platform.names.resolve(`${name}.dash`)
if (result !== null) {
res.json(result.toJSON())
} else {
res.status(404).send(`No identity found with the name: ${name}.dash`)
}
} catch (error) {
console.error(error)
res.status(500).send('Something went wrong:\n' + error)
}
})
const port = process.env.PORT || 3001
app.listen(port, () => {
console.log("Running on localhost:", port)
})
process.on('SIGINT', async () => {
console.log('Disconnecting Dash client...')
await client.disconnect()
process.exit(0)
})

Start the server with the following command:

Terminal window
npm run express

Open localhost:3001/name/ajcwebdev or send a GET request with curl.

Terminal window
curl "http://localhost:3001/name/ajcwebdev"

Create Next App

Now that’s add a frontend. We’ll use Next.js to build a React based frontend.

Terminal window
npx create-next-app@latest next

Open page.js in next/src/app and include the following code:

next/src/app/page.js
const main = "flex flex-col items-center justify-between p-24"
const header = "text-3xl"
const pageContent = "z-10 max-w-5xl w-full items-center justify-between font-sans lg:flex"
export default function Home() {
return (
<main className={main}>
<h1 className={header}>Next.js Dash Example</h1>
<div className={pageContent}>
<h2>Identity:</h2>
</div>
</main>
)
}

Start your server with the following command:

Terminal window
npm run dev

Setup React Project Structure

Now let’s include the logic to fetch our name.

next/src/app/page.js
"use client"
import { useEffect, useState } from 'react'
const main = "flex flex-col items-center justify-between p-24"
const header = "text-3xl"
const pageContent = "z-10 max-w-5xl w-full items-center justify-between font-sans lg:flex"
export default function Home() {
const [blockchainData, setBlockchainData] = useState(null)
useEffect(() => {
fetch('http://localhost:3001/name/ajcwebdev')
.then(response => response.json())
.then(data => setBlockchainData(data))
}, [])
return (
<main className={main}>
<h1 className={header}>Next.js Dash Example</h1>
<div className={pageContent}>
<h2>Identity:</h2>
<pre>
{JSON.stringify(blockchainData, null, 2)}
</pre>
</div>
</main>
)
}

Add Fetch Button to React App

Now lets add a button that when clicked will fetch our name information.

next/src/app/page.js
"use client"
import { useEffect, useState } from 'react'
const main = "flex flex-col items-center justify-between p-24"
const header = "text-3xl"
const pageContent = "z-10 max-w-5xl w-full items-center justify-between font-sans lg:flex"
export default function Home() {
const [blockchainData, setBlockchainData] = useState()
const [triggerFetch, setTriggerFetch] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const fetchData = () => {
setIsLoading(true) // Set loading to true when fetch begins
fetch('http://localhost:3001/name/ajcwebdev')
.then(response => response.json())
.then(data => {
setBlockchainData(data)
setIsLoading(false) // Set loading to false when fetch completes
})
}
useEffect(() => {
if (triggerFetch) {
fetchData()
setTriggerFetch(false) // Reset trigger
}
}, [triggerFetch])
return (
<main className={main}>
<h1 className={header}>Next.js Dash Example</h1>
<div className={pageContent}>
<h2>Identity:</h2>
<button onClick={() => setTriggerFetch(true)}>
Fetch Data
</button>
<pre>
{isLoading
? 'Loading...'
: JSON.stringify(blockchainData, null, 2)
}
</pre>
</div>
</main>
)
}

Wow, you made it all the way to the end! Great job!! In future blog posts we’ll expand out our frontend to include more of the functionality included in our Node scripts. We’ll also build out frontends with other popular frameworks.