Web3 store

Published: (January 10, 2026 at 06:41 AM EST)
2 min read
Source: Dev.to

Source: Dev.to

Overview

I wrote and deployed a demo Web3 store using Solidity and ethers.js as a learning exercise. The original tools recommended by an older book (web3.js, Truffle, Ganache) are now obsolete, so I built the project with modern tooling.

Setup

Choosing a Development Framework

For building and deploying smart contracts, I selected Forge (part of Foundry) over Hardhat. Both provide local testnets; I used Anvil, Forge’s fast, in‑memory Ethereum node.

Start Anvil from the console; it automatically creates funded accounts and prints the RPC endpoint (e.g., http://127.0.0.1:8545) that MetaMask can connect to.

Smart Contract

The contract implements two functions:

Purchase an Item

function purchaseItem(uint8 _itemId) external payable {
    uint256 itemCost = 2 gwei; // 0.0012 USD / 0.18 RUB;

    // Forward the funds to the seller
    (bool success, ) = STORE_ADDRESS.call{value: itemCost}("");
    require(success, "Transfer failed");

    boughtItems[msg.sender].push(_itemId);
}

View Purchased Items

function getBoughtItems() external view returns (uint8[] memory) {
    return boughtItems[msg.sender];
}

Deploying the Contract

After testing and compilation, publish the contract with Forge:

forge create ./src/Store.sol:Store \
    --private-key  \
    --rpc-url  \
    --broadcast \
    --constructor-args 

The command returns the deployed contract address.

Frontend Integration

The store application uses ethers v6 to interact with MetaMask and the blockchain.

Initialize Provider and Signer

import { ethers } from "ethers";

const provider = new ethers.BrowserProvider(window.ethereum);
const signerObj = await provider.getSigner();
const balance = await provider.getBalance(signerObj.address);
const balanceFormatted = ethers.formatEther(balance);

Load Contract ABI

import ContractArtifact from "***/Store.json";
const abi = ContractArtifact.abi;

Create Contract Instance

const contract = new ethers.Contract(CONTRACT_ADDRESS, abi, signerObj);

Call Contract Functions

Purchase an Item

contract.purchaseItem(itemId, {
    value: ethers.parseUnits("2", "gwei") // attach the wei
}).then((tx) => tx.wait())
  .then(() => {
      const newItems = items.add(itemId);
      setItems(newItems);
  });

Retrieve Purchased Items

const userItems = await contract.getBoughtItems();

Deployment to Live Network

Once development is complete, the store and its contract can be deployed to a live network using the same Forge workflow, updating the RPC URL and private key accordingly.

Thanks for reading! Any feedback or suggestions are appreciated.

Project link:

Back to Blog

Related posts

Read more »

Ethereum UX: Account Abstraction (AA)

Introduction If you have been in the Web3 community for a while, you might have heard about Account Abstraction AA. If you are just a Web2 user, stepping into...

Wallets Are the New Auth Layer

Introduction If you have implemented authentication in Web2, Web3 wallets should not feel strange. Authentication has always been about one thing: Can this use...