<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Future: Arturas-Alfredas Lapinskas</title>
    <description>The latest articles on Future by Arturas-Alfredas Lapinskas (@yaalfred).</description>
    <link>https://future.forem.com/yaalfred</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F371737%2Fc2f71937-6e62-4ad4-95a9-317d32f24deb.png</url>
      <title>Future: Arturas-Alfredas Lapinskas</title>
      <link>https://future.forem.com/yaalfred</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://future.forem.com/feed/yaalfred"/>
    <language>en</language>
    <item>
      <title>A Database‑Free Web3 Store: MetaMask Authentication and On‑Chain Product Management</title>
      <dc:creator>Arturas-Alfredas Lapinskas</dc:creator>
      <pubDate>Sat, 10 Jan 2026 11:41:51 +0000</pubDate>
      <link>https://future.forem.com/yaalfred/web3-store-4c15</link>
      <guid>https://future.forem.com/yaalfred/web3-store-4c15</guid>
      <description>&lt;p&gt;I wrote and deployed a demo Web3 store with Solidity and ethers.js.&lt;br&gt;
Users can log in using MetaMask and make purchases.&lt;br&gt;
The store runs without a database; all transaction data is stored on‑chain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczcrbr4yi43orfvqs8ha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczcrbr4yi43orfvqs8ha.png" alt="metamask transaction" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrd8qeixwlx68ytahbx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrd8qeixwlx68ytahbx9.png" alt="metamask transaction" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The store was created for learning about solidity and working with smart contracts.&lt;/p&gt;

&lt;p&gt;Unfortunately, the book I bought few years ago and the tools it recommends (web3.js, Truffle, Ganache) are now obsolete and no longer maintained, so I had to figure everything out on my own. &lt;/p&gt;

&lt;p&gt;First, we needed a tools for develop smart contracts. Modern options are Foundry and Hardhat3; &lt;/p&gt;

&lt;p&gt;A testnet is required for development. Both Hardhat and Foundry provide built‑in local testnets; I used Anvil, Foundry’s fast, in‑memory Ethereum node. &lt;/p&gt;

&lt;p&gt;Anvil is started from the console. It automatically creates funded accounts and prints the RPC endpoint (e.g., &lt;a href="http://127.0.0.1:8545" rel="noopener noreferrer"&gt;http://127.0.0.1:8545&lt;/a&gt;) that MetaMask can connect to. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwpr9djgl72rz9roo9i9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwpr9djgl72rz9roo9i9.png" alt="Anvil output" width="800" height="403"&gt;&lt;/a&gt;&lt;br&gt;
Connect the MetaMask extension to the RPC URL shown by Anvil, then deploy the compiled contract to that network.&lt;/p&gt;

&lt;p&gt;For the contract, we need two functions:&lt;/p&gt;

&lt;p&gt;1.Purchase an item. The purchase will transfer funds to the store wallet and record the ID of the purchased item for the buyer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.View purchased items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getBoughtItems() external view returns (uint8[] memory) {
    return boughtItems[msg.sender];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For building, testing and publishing you can use forge from Foundry framework. I won't provide tests here. After successful testing and compilation, publish the contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge create ./src/Store.sol:Store \
    --private-key &amp;lt;PRIVATE_KEY&amp;gt; \
    --rpc-url &amp;lt;RPC_URL&amp;gt; \
    --broadcast \
    --constructor-args &amp;lt;STORE_PUBLIC_KEY&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After successful publication, we are given the smart contract address.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ob5qy7s3460xc9bcpum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ob5qy7s3460xc9bcpum.png" alt="smart contract address" width="800" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we'll write the store application. We'll need a library to interact with MetaMask and the blockchain. I used Ethers v6, as I found it to be the most well-documented.&lt;br&gt;
First, connect to the Ethereum wallet through the MetaMask extension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const provider = new ethers.BrowserProvider(window.ethereum); 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Query the balance to ensure it's working correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const signerObj = await provider.getSigner();
const balance = await provider.getBalance(signerObj.address);        
const balanceFormatted = ethers.formatEther(balance);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, interact with the smart contract.&lt;br&gt;
1.Import abi – a json from the solidity build result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import ContractArtifact from "***/Store.json";
const abi = ContractArtifact.abi;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.Create an Contract instance and pass it the smart contract address we received after publish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const contract = new ethers.Contract(CONTRACT_ADDRESS, abi, signerObj);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.That's it, you can call the smart contract's functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract.purchaseItem(itemId, {
    value: ethers.parseUnits("2", "gwei")   // &amp;lt;-- attach the wei
}).then((tx) =&amp;gt; {
    return tx.wait();
}).then(() =&amp;gt; {
    const newItems = items.add(itemId);
    setItems(newItems);
});

const userItems = await contract.getBoughtItems();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the work is complete, you can deploy the store and contract to the live network.&lt;/p&gt;

&lt;p&gt;Thanks for reading, any feedback or suggestions are appreciated. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ALapinskas/gh-rts" rel="noopener noreferrer"&gt;Project link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ether</category>
      <category>solidity</category>
      <category>blockchain</category>
    </item>
  </channel>
</rss>
