Interacting with Your Deployed Move Smart Contract

In this guide, we will create a simple website that interacts with your deployed Move smart contract. The website will allow users to increment the counter and display its current value using Move transactions and Viem SDK.

1. Setting Up the Next.js Project

  1. Create a new Next.js project with TypeScript:
    npx create-next-app@latest my-move-dapp --typescript
    cd my-move-dapp
    
  2. Install the required dependencies:
    npm install @aptos-labs/ts-sdk viem
    

2. Building the Web Interface

  1. Create a simple UI with an input field, buttons, and a display for the counter value.
  2. Add a function to fetch the current counter value from the smart contract using Viem.
  3. Implement a function to send a transaction that increments the counter.

Example Code (Counter Interaction)

Create a new file src/app/Counter.tsx:

'use client';
import { useEffect, useState } from 'react';
import { littleEndianU8ArrayToU64, counterPayload, getAccount, publicClient, walletClient } from '@/config';

export default function Counter() {
  const [counter, setCounter] = useState(0);

  const fetchCounter = async () => {
    const callResponse = await publicClient().call({
      to: await getAccount(),
      data: await counterPayload('get'),
    });

    const data = callResponse.data?.slice(2, 10) as Uint8Array | undefined;
    if (data) {
      const num = littleEndianU8ArrayToU64(data);
      setCounter(num);
    }
  };

  const incrementCounter = async () => {
    const hash = await walletClient().sendTransaction({
      account: await getAccount(),
      to: await getAccount(),
      data: await counterPayload('increment'),
    });
    await publicClient().waitForTransactionReceipt({ hash });
    fetchCounter();
  };

  useEffect(() => {
    fetchCounter();
  }, []);

  return (
    <div className="text-center m-24">
      <h1 className="py-6">Counter: {counter}</h1>
      <button className="bg-blue-700 rounded-lg px-5 py-2.5" type="button" onClick={incrementCounter}>
        Increment
      </button>
    </div>
  );
}

3. Integrating the Counter Component

Replace the contents of src/app/page.tsx with:

import Counter from "./Counter";

export default function Home() {
  return (
    <div>
      <h1>Move Counter DApp</h1>
      <Counter />
    </div>
  );
}

4. Adding Configuration for Transactions

Create a new file config.ts to define methods for creating a transaction payload and sending transactions using the Viem SDK.

import { AccountAddress, EntryFunction, TransactionPayloadEntryFunction } from '@aptos-labs/ts-sdk';
import { createPublicClient, createWalletClient, custom, defineChain } from 'viem';
import { publicActionsL2, walletActionsL2 } from 'viem/op-stack';

export const devnet = defineChain({
  id: 42069,
  sourceId: 42069,
  name: 'Moved',
  nativeCurrency: {
    decimals: 18,
    name: 'Ether',
    symbol: 'ETH',
  },
  rpcUrls: {
    default: {
      http: ['https://devnet.moved.network'],
    },
  },
});

export const getAccount = async () => {
  const [account] = await window.ethereum!.request({
    method: 'eth_requestAccounts',
  });

  return account;
};

export const getMoveAccount = async () => {
  const account = await getAccount();
  const moveAccount = account.slice(0, 2) + '000000000000000000000000' + account.slice(2);
  return moveAccount;
};

export const publicClient = () =>
  createPublicClient({
    chain: devnet,
    transport: custom(window.ethereum!),
  }).extend(publicActionsL2());

export const walletClient = () =>
  createWalletClient({
    chain: devnet,
    transport: custom(window.ethereum!),
  }).extend(walletActionsL2());

export const counterPayload = async (method: string) => {
  const moveAccount = await getMoveAccount();
  const entryFunction = EntryFunction.build(
    `${moveAccount}::counter`,
    method,
    [],
    [AccountAddress.fromString(moveAccount)],
  );
  const transactionPayload = new TransactionPayloadEntryFunction(entryFunction);
  return transactionPayload.bcsToHex().toString() as `0x${string}`;
};

export const littleEndianU8ArrayToU64 = (array: Uint8Array) => {
  if (array.length != 8) throw Error('U8 array length should be 8 to make up a U64');
  let num = array[0];
  for (let i = 1; i < 8; i++) {
    num = (array[i] << (i * 8)) | num;
  }
  return num;
};

4. Running the Website

Start the development server:

npm run dev

Open http://localhost:3000 in your browser to interact with the contract.

Conclusion

You've successfully created a simple Next.js website to interact with your Move smart contract. Users can now send transactions to increment the counter and retrieve its value. In the next section, we will explore deploying this website for public access.

© 2025 Moved, Inc.