[astar] next.js + polkadot.js

Realtakahashi Work
7 min readJul 20, 2022

--

Summary

Today I introduce to implementing front-end application with “next.js” using polkadot.js.

  1. Create a next.js project and implement the “flipper” front-end interface application.
  2. Run the Astar Network node on the local pc.
  3. Deploy the “flipper” contract to the Astar node.
  4. Test the front-end application.

1. Create a next.js project and implement the “flipper” front-end interface application.

Create a project

  • Create next.js project.
npx create-next-app flipper_nextjs --typescript
  • When your command is succeed,You execute the next.js application by the command as following.
% cd flipper_nextjs
% yarn dev

Apply tailwind.css

  • Next,We apply tailwind.css on this project.
% npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
% npx tailwindcss init -p
  • After you execute above commands,You can find “tailwind.config.js” file. You edit the file as following.
module.exports = {
mode: 'jit',
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
  • You edit “style/globals.css” as following. Then you can use “tailwind” in your project.
@tailwind base;
@tailwind components;
@tailwind utilities;

Start “flipper” contract front-end interface

  • At first, You open “pages/index.tsx” file and you erase all code.
  • You implement skeleton code as following.
const Home = () => {
return (
<>
</>
);
}
export default Home;
  • Now we can start to implement.
  • At first we implement “setup” function and HTML interface which get block header information from blockchain and show the information.
import { useEffect, useState } from "react";
import { ApiPromise, Keyring, WsProvider } from "@polkadot/api";
const Home = () => {
const [block, setBlock] = useState(0);
const [lastBlockHash, setLastBlockHash] = useState("");
const [blockchainUrl, setBlockchainUrl] = useState("ws://127.0.0.1:9944");
const [api, setApi] = useState<any>();
const setup = async () => {
const wsProvider = new WsProvider(blockchainUrl);
const api = await ApiPromise.create({ provider: wsProvider });
await api.rpc.chain.subscribeNewHeads((lastHeader) => {
setBlock(lastHeader.number.toNumber());
setLastBlockHash(lastHeader.hash.toString());
});
setApi(api);
// await extensionSetup();
};
useEffect(() => {
setup();
});
return (
<>
<div className="text-center">
<div className="p-3 m-3 text-3xl">flipper test</div>
<div className="p-3 m-3">Block: {block}</div>
<div className="p-3 m-3">Blockchain URL: {blockchainUrl}</div>
<div className="">Custom Blockchain URL</div>
<button
className="bg-green-900 hover:bg-green-800 text-white rounded px-4 py-2"
onClick={setup}
>
Change Blockchain URL
</button>
<input
className="p-2 m-2 border-2"
onChange={(event) => setBlockchainUrl(event.target.value)}
/>
<div className="p-3 m-3">Last block hash: {lastBlockHash}</div>
</div>
</>
);
};
export default Home;
  • If you compile this code in this condition, you get an error. So, We install dependency libraries.
% yarn add @polkadot/api
  • Then let’s compile this project.
% yarn build
  • When at this stage we execute this project after astar node is run at local, you can see as following screen and you can check block number is increased.
  • I introduce how to execute astar node later.
  • Next, we add implementing “extentionSetup” function that get account information from polkadot.js extention.
  • You add following code at import area.
import type { InjectedAccountWithMeta } from "@polkadot/extension-inject/types";
  • Also add to useState following code.
const [accounts, setAccounts] = useState<InjectedAccountWithMeta[]>([]);
const [actingAddress, setActingAddress] = useState("");
  • Let’ add “extensionSetup” function code.
const extensionSetup = async () => {
const { web3Accounts, web3Enable } = await import(
"@polkadot/extension-dapp"
);
const extensions = await web3Enable("Polk4NET");
if (extensions.length === 0) {
return;
}
const account = await web3Accounts();
setAccounts(account);
};
  • Uncomment the code which call “extentionSetup” in “setup” function.
const setup = async () => {
-- snip --
await extensionSetup();
};

Attention: Following code shows “dynamic import”. Next.js is server-side rendering framework, so if you import this library statically, you get a “Reference Error”.

const { web3Accounts, web3Enable } = await import(
"@polkadot/extension-dapp"
);
  • Just like before, we install dependencies libraries.
% yarn add @polkadot/extension-inject
% yarn add @polkadot/extension-dapp
  • Also add HTML interface of accounts.
        <select
className="p-3 m-3 border-2 border-green-500"
onChange={(event) => {
console.log(event);
setActingAddress(event.target.value);
}}
>
{accounts.map((a) => (
<option key={a.address} value={a.address}>
{a.address} [{a.meta.name}]
</option>
))}
</select>
  • You can find account part at the screen.
  • We will implement an interface that calls the “flipper” contract.
  • Add the following import part.
import { ContractPromise } from "@polkadot/api-contract";
import abi from "../change_with_your_own_metadata.json";
  • Add the following useState.
  const [result, setResult] = useState("");
const [gasConsumed, setGasConsumed] = useState("");
const [outcome, setOutcome] = useState("");
const [contractAddress, setContractAddress] = useState("");
  • Then add a function “getFlipValue” to get the value from the “flipper” contract.
  const getFlipValue = async () => {
const contract = new ContractPromise(api, abi, contractAddress);
const { gasConsumed, result, output } = await contract.query.get(
actingAddress,
{ value: 0, gasLimit: -1 }
);
setGasConsumed(gasConsumed.toHuman());
setResult(JSON.stringify(result.toHuman()));
if (output !== undefined && output !== null) {
setOutcome(output.toHuman()?.toString() ?? "");
}
};
  • Also add the following function to execute the “flipper” transaction.
  const changeFlipValue = async () => {
const { web3FromSource } = await import("@polkadot/extension-dapp");
const contract = new ContractPromise(api, abi, contractAddress);
const performingAccount = accounts[0];
const injector = await web3FromSource(performingAccount.meta.source);
const flip = await contract.tx.flip({ value: 0, gasLimit: -1 });
if (injector !== undefined) {
flip.signAndSend(
performingAccount.address,
{ signer: injector.signer },
(result) => {
if (result.status.isInBlock) {
setResult("in a block");
} else if (result.status.isFinalized) {
setResult("finalized");
}
}
);
}
};
  • And finally, add an HTML interface that calls these functions.
<div className="p-3 m-3">
Input contract address (from your canvas UI after you instantiate it):{" "}
{contractAddress}
</div>
<input
className="p-2 m-2 border-2"
onChange={(event) => setContractAddress(event.target.value)}
/>
<br />
<br />
<br />
<button
className="bg-green-900 hover:bg-green-800 text-white rounded px-4 py-2"
disabled={!api || !contractAddress}
onClick={getFlipValue}
>
{api && contractAddress
? "Get flip value!"
: "Couldn't load API or contract address is invalid, please see logs in console."}
</button>
<br />
<br />
<button
className="bg-green-900 hover:bg-green-800 text-white rounded px-4 py-2"
disabled={!api || !contractAddress}
onClick={changeFlipValue}
>
{api && contractAddress
? "Change flip value!"
: "Couldn't load API or contract address is invalid, please see logs in console."}
</button>
<div>Result: {result}</div>
<div>Outcome: {outcome}</div>
<div>Gas consumed: {gasConsumed}</div>
  • Install dependent libraries. Then build.
yarn add @polkadot/api-contract

2. Run the Astar Network node on the local pc.

  • Run the local node by referring to “Deploy the smart contract on Astar Node” in the following article.
% ./astar-collator --dev

3. Deploy the “flipper” contract to the Astar node.

  • Deploy the “flipper” contract to your local Astar Node by referring to the following article.

4. Test the front-end application.

  • Run the front-end application implemented this time.
yarn dev
  • Access “http://localhost:3000”.
  • And you can call the “flipper” contract by copying the address of the contract you deployed to your local node and pasting it into the “Input contract address” text box.
  • Click “Get flip value!” To see the default values ​​at deployment time.
  • Then click “Change flip value!” To execute the transaction.
  • When the polkadot extension is launched and signed, the transaction is executed.
  • Click “Get flip value!” Again to get the changed value.
  • Sample Code

Next Step

I would like to continue to catch up on Astar Network related technologies. First of all, I would like to confirm “Swanky” which is the integrated environment of WASM announced yesterday. And I’m thinking of implementing the dApp I’m thinking about with WASM.

At the same time, I would like to upgrade the DAO tools implemented in EVM. See the following articles for my DAO tools.

About Astar Network

Astar Network — the Innovation Hub on Polkadot. Astar Network supports the building of dApps with EVM and WASM smart contracts and offers developers true interoperability, with cross-consensus messaging (XCM). We are made by developers and for developers. Astar’s unique Build2Earn model empowers developers to get paid through a dApp staking mechanism for the code they write and dApps they build.

Astar’s vibrant ecosystem has become Polkadot’s leading Parachain globally, supported by all major exchanges and tier 1 VCs. Astar offers the flexibility of all Ethereum and WASM toolings for developers to start building their dApps. To accelerate growth on Polkadot and Kusama Networks, Astar Space Labs offers an Incubation Hub for top TVL dApps.

Website | Twitter | Discord | Telegram | GitHub

--

--