A Product Manager's exploration of modern IT: from the code and security of applications to the strategy behind Web3, blockchain, and NFTs.

Subscribe to NICK SAPEROV XYZ
<100 subscribers
<100 subscribers


Several months ago, I published an article about my first steps into Web3—launching a simple, static personal page on a distributed network. Since then, my knowledge in the tech and Web3 fields has grown exponentially. I recently built a more comprehensive portfolio using a standard Web2 tool, WordPress, and decided to get an ENS name for it.
My first thought was simple: why not register a static copy of my new Web2 portfolio on-chain using the app.ens service? It turned out this process was anything but straightforward. After trying several methods and hitting numerous dead ends, I was deeply frustrated. This friction felt like a significant barrier for anyone wanting to bridge their Web2 presence to Web3.
That’s when I decided to pivot. I realized the core bottleneck wasn’t just a conversion tool, but the lack of a flexible, simple way to register any kind of content metadata on-chain. I decided to tackle the root of the problem first: to build a simple, robust, and open-ended Content Registry dApp. This would be a foundational tool that could, in the future, power the very Web2-to-Web3 bridge I was trying to cross.
What follows is not just a technical summary, but a case study in resilience, problem-solving, and end-to-end product delivery.
The goal was to deploy a serverless dApp that allows users to register data (ENS name, IPFS CID, Version, Status) to a smart contract on the Sepolia testnet. The frontend was simple HTML/CSS and Ethers.js.
My development environment is Google Cloud Shell, as my hardware doesn’t support local virtualization. This powerful cloud tool provides a terminal, editor, and web preview. However, the journey began with an immediate and unexpected challenge: the environment itself was hostile.
The process started with a cascade of errors. The default Node.js version in Cloud Shell was a bleeding-edge, unsupported release (v22), and the latest versions of Hardhat required a conflicting ES Module (ESM) setup. Standard npm install commands repeatedly failed with ERESOLVE errors. Debugging the environment consumed a significant portion of the project’s timeline.
To create a stable environment, I had to systematically:
Downgrade Node.js to a supported LTS version (v18) using nvm.
Pin package versions to a known-stable, older release of Hardhat (hardhat@2.19.4).
Use the –legacy-peer-deps flag with npm to bypass dependency resolution bugs.
Manually install all peer dependencies in a brute-force approach.
With a stable backend environment, I built a simple UI. This next phase came with its own set of classic developer hurdles.
The first was a common TypeError in the JavaScript, caused by the script trying to access HTML elements before the DOM was fully loaded. Fixing this was a critical lesson in script loading order. Using the Chrome Developer Console was invaluable for tracing the source of the error and making the necessary code adjustments.
Next, to prepare for deployment, I pushed the code to GitHub. This required replacing legacy password authentication with a modern security best practice: a Fine-grained Personal Access Token (PAT).
Finally, the project was deployed using Netlify. I configured it to pull from the dapp/ folder in my repository, enabling a smooth, continuous deployment pipeline.
With the dApp live, I began testing. I clicked the “Connect Wallet” button and… nothing happened. The backend was solid, the frontend logic was verified, but the dApp was unresponsive. It was a moment of pure frustration.
Drawing on past user experience, I remembered encountering this behavior before. The cause was often a “provider collision” from having multiple wallet extensions enabled at once. I disabled all my wallets except MetaMask, and on the next – voilà – it connected instantly.
This final bug highlighted a critical UX problem in the Web3 space. When multiple wallets are active, they “fight” over the window.ethereum object in the browser, causing connection failures.
The professional solution to this is EIP-6963: Multi-Injected Provider Discovery. This standard allows each wallet to announce its presence without overwriting others, enabling a dApp to detect all installed wallets and let the user choose which one to use. Implementing EIP-6963 is a clear next step for this project to ensure a seamless experience for all users, demonstrating the importance of building for the realities of the ecosystem.
You can check the dApp here:
https://web3-content-registry-dapp.netlify.app/
Several months ago, I published an article about my first steps into Web3—launching a simple, static personal page on a distributed network. Since then, my knowledge in the tech and Web3 fields has grown exponentially. I recently built a more comprehensive portfolio using a standard Web2 tool, WordPress, and decided to get an ENS name for it.
My first thought was simple: why not register a static copy of my new Web2 portfolio on-chain using the app.ens service? It turned out this process was anything but straightforward. After trying several methods and hitting numerous dead ends, I was deeply frustrated. This friction felt like a significant barrier for anyone wanting to bridge their Web2 presence to Web3.
That’s when I decided to pivot. I realized the core bottleneck wasn’t just a conversion tool, but the lack of a flexible, simple way to register any kind of content metadata on-chain. I decided to tackle the root of the problem first: to build a simple, robust, and open-ended Content Registry dApp. This would be a foundational tool that could, in the future, power the very Web2-to-Web3 bridge I was trying to cross.
What follows is not just a technical summary, but a case study in resilience, problem-solving, and end-to-end product delivery.
The goal was to deploy a serverless dApp that allows users to register data (ENS name, IPFS CID, Version, Status) to a smart contract on the Sepolia testnet. The frontend was simple HTML/CSS and Ethers.js.
My development environment is Google Cloud Shell, as my hardware doesn’t support local virtualization. This powerful cloud tool provides a terminal, editor, and web preview. However, the journey began with an immediate and unexpected challenge: the environment itself was hostile.
The process started with a cascade of errors. The default Node.js version in Cloud Shell was a bleeding-edge, unsupported release (v22), and the latest versions of Hardhat required a conflicting ES Module (ESM) setup. Standard npm install commands repeatedly failed with ERESOLVE errors. Debugging the environment consumed a significant portion of the project’s timeline.
To create a stable environment, I had to systematically:
Downgrade Node.js to a supported LTS version (v18) using nvm.
Pin package versions to a known-stable, older release of Hardhat (hardhat@2.19.4).
Use the –legacy-peer-deps flag with npm to bypass dependency resolution bugs.
Manually install all peer dependencies in a brute-force approach.
With a stable backend environment, I built a simple UI. This next phase came with its own set of classic developer hurdles.
The first was a common TypeError in the JavaScript, caused by the script trying to access HTML elements before the DOM was fully loaded. Fixing this was a critical lesson in script loading order. Using the Chrome Developer Console was invaluable for tracing the source of the error and making the necessary code adjustments.
Next, to prepare for deployment, I pushed the code to GitHub. This required replacing legacy password authentication with a modern security best practice: a Fine-grained Personal Access Token (PAT).
Finally, the project was deployed using Netlify. I configured it to pull from the dapp/ folder in my repository, enabling a smooth, continuous deployment pipeline.
With the dApp live, I began testing. I clicked the “Connect Wallet” button and… nothing happened. The backend was solid, the frontend logic was verified, but the dApp was unresponsive. It was a moment of pure frustration.
Drawing on past user experience, I remembered encountering this behavior before. The cause was often a “provider collision” from having multiple wallet extensions enabled at once. I disabled all my wallets except MetaMask, and on the next – voilà – it connected instantly.
This final bug highlighted a critical UX problem in the Web3 space. When multiple wallets are active, they “fight” over the window.ethereum object in the browser, causing connection failures.
The professional solution to this is EIP-6963: Multi-Injected Provider Discovery. This standard allows each wallet to announce its presence without overwriting others, enabling a dApp to detect all installed wallets and let the user choose which one to use. Implementing EIP-6963 is a clear next step for this project to ensure a seamless experience for all users, demonstrating the importance of building for the realities of the ecosystem.
You can check the dApp here:
https://web3-content-registry-dapp.netlify.app/
Share Dialog
Share Dialog
No activity yet