I spent last week trying to understand how .night domains actually work. Not from a spec sheet, but by building something that touches the chain directly. The result is a small profile viewer. You type in a name like tomin.night, and it resolves the profile straight from the blockchain. No registrar API. No auth wall. Just a smart contract and some JavaScript.

What follows is how it works, what I learned, and the two specific traps that ate my afternoon.

Why On-Chain Names Matter

On Midnight, .night domains are managed by Midnames. Instead of querying a company’s central server, you read directly from a smart contract that lives on the chain. The registry itself holds the domain, the owner, and whatever profile fields the owner attached. Because that data is on-chain, the identity is portable. You are not renting it from a platform that can change terms or pull the plug. If you control the keys, you control the name.

That shift matters for developers too. When you build against a traditional DNS system, you deal with rate limits, API keys, and uptime promises. Here, the contract state is the source of truth. Your application reads it the same way every other application reads it. There is no privileged API tier.

The Code Is Almost Too Simple

The @midnames/sdk handles the heavy lifting. Resolving a domain to an address and profile takes exactly two lines:

const provider = createDefaultProvider({ networkId: "mainnet" });
const result = await resolveDomain(provider, "tomin.night");

That is it. The provider targets the network, and the resolver talks to the contract. The SDK returns a result object that includes a success flag. If the domain does not exist, you do not need layers of error handling or try-catch blocks around RPC failures. The SDK tells you cleanly that nothing is there. This makes building UIs surprisingly pleasant. You can branch on the success flag and show a “not found” state without guessing whether the failure was a missing name or a dead node.

What You Get Back

When the lookup succeeds, the payload contains two pieces that matter.

Target is the wallet address the domain points to. This is the core utility. It turns a long hex address into something a human can read, type, and remember.

Fields hold the profile details. Whatever the owner attached to the domain—social links, avatars, text records—lives inside this structure. These fields are not stored on some company’s MongoDB cluster. They are fields in the contract state, which means any app that knows how to read the registry can render the same profile. No database sync required.

Two Traps That Slowed Me Down

Not everything about the build was two lines and a success flag. I hit two specific hurdles that are worth spelling out so you do not repeat them.

Network Mismatch

The SDK supports both mainnet and preprod environments. I spent a solid chunk of time debugging a domain that “did not exist.” The name was correct. The code looked right. The provider was running. The problem was that my script was querying preprod while the domain itself was registered on mainnet. The error looked like a missing domain, but it was really a missing network context.

If you are resolving a name and getting back a failure, check the provider settings before you debug anything else. Make sure your networkId matches the network where the domain is actually minted. This is the kind of mistake that feels obvious in retrospect but is genuinely hard to spot when you are assuming the contract logic is the issue.

Serialization Pain

The data that comes back from the SDK is not standard JavaScript. It contains BigInt values and Map objects. If you try to pipe that straight into JSON.stringify to send it to a browser, it will throw or silently drop data. BigInt has no native JSON representation, and Map does not serialize the way plain objects do.

I ended up writing a custom serializer. It walks the result object, converts BigInt values to strings, and transforms Map instances into regular objects before the response leaves the server. If you are building an API that serves Midnight data to a frontend, plan for this step early. Do not assume the SDK output is immediately frontend-friendly just because it is JavaScript.

The Architecture

ನಾನು ಸ್ಟ್ಯಾಕ್ ಅನ್ನು ಉದ್ದೇಶಪೂರ್ವಕವಾಗಿ ಸರಳವಾಗಿಟ್ಟಿದ್ದೇನೆ. ಬ್ಯಾಕೆಂಡ್ ಎಕ್ಸ್‌ಪ್ರೆಸ್ (Express) ಚಾಲನೆಯಲ್ಲಿರುವ ಒಂದು ನೋಡ್ (Node) ಸರ್ವರ್ ಆಗಿದೆ. ಇದು @midnames/sdk ಅನ್ನು ಇಂಪೋರ್ಟ್ ಮಾಡುತ್ತದೆ, ರೆಸಲ್ಯೂಶನ್ ಲಾಜಿಕ್ ಅನ್ನು ರನ್ ಮಾಡುತ್ತದೆ, ಸೀರಿಯಲೈಸೇಶನ್ (serialization) ಪ್ರಕ್ರಿಯೆಗಳನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ ಮತ್ತು ಕ್ಲೀನ್ JSON ಅನ್ನು ನೀಡುತ್ತದೆ. ಫ್ರಂಟ್‌ಎಂಡ್ ಸರಳ HTML ಮತ್ತು ವ್ಯಾನಿಲಾ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ (vanilla JavaScript) ಆಗಿದೆ. ಯಾವುದೇ ಬಿಲ್ಡ್ ಸ್ಟೆಪ್ ಇಲ್ಲ. ಯಾವುದೇ ಫ್ರೇಮ್‌ವರ್ಕ್ ಇಲ್ಲ. ಯಾವುದೇ ವ್ಯಾಲೆಟ್ ಅಡಾಪ್ಟರ್ ಇಲ್ಲ.

ಕೆಲವು ಪ್ರಾಯೋಗಿಕ ಕಾರಣಗಳಿಗಾಗಿ ನಾನು ಬ್ರೌಸರ್ ಬದಲಿಗೆ ಬ್ಯಾಕೆಂಡ್‌ನಲ್ಲಿ SDK ಅನ್ನು ರನ್ ಮಾಡಲು ನಿರ್ಧರಿಸಿದೆ. ಇದು ಯಾವುದೇ ಪ್ರೊವೈಡರ್ ಕಾನ್ಫಿಗರೇಶನ್ ಅನ್ನು ಕ್ಲೈಂಟ್‌ನಿಂದ ದೂರವಿಡುತ್ತದೆ, ಸೀರಿಯಲೈಸೇಶನ್ ಗೊಂದಲವನ್ನು ಸರಿಪಡಿಸಲು ನನಗೆ ಒಂದೇ ಸ್ಥಳವನ್ನು ನೀಡುತ್ತದೆ ಮತ್ತು ಫ್ರಂಟ್‌ಎಂಡ್ ಕೇವಲ ಡೇಟಾವನ್ನು ಫೆಚ್ ಮಾಡಿ ಅದನ್ನು ರেন্ডರ್ ಮಾಡಬೇಕಷ್ಟೇ ಎಂಬ ಅರ್ಥವನ್ನು ನೀಡುತ್ತದೆ.

ನನಗೆ ಅಚ್ಚರಿ ಮೂಡಿಸಿದ ಭಾಗವೆಂದರೆ: ಹೆಸರನ್ನು ರೆಸೋಲ್ವ್ ಮಾಡುವುದು ಒಂದು ಪಬ್ಲಿಕ್ ರೀಡ್ ಆಪರೇಷನ್ ಆಗಿದೆ. ಇದಕ್ಕೆ ವ್ಯಾಲೆಟ್ ಕನೆಕ್ಷನ್ ಅಗತ್ಯವಿಲ್ಲ. ಸಹಿ (signature) ಅಗತ್ಯವಿಲ್ಲ. ಬಳಕೆದಾರರು ಯಾವುದರ ಮೂಲಕವೂ ಲಾಗಿನ್ ಆಗಬೇಕೆಂದೂ ಅಗತ್ಯವಿಲ್ಲ. ಡೊಮೇನ್ ಇದ್ದರೆ, ಕಾಂಟ್ರಾಕ್ಟ್ ಸ್ಟೇಟ್ ಕೇಳುವ ಯಾರಿಗಾದರೂ ಕಾಣಿಸುತ್ತದೆ. ಪ್ರತಿಯೊಂದು ಇಂಟರಾಕ್ಷನ್ ಕೂಡ “connect wallet” ಎಂಬದರೊಂದಿಗೆ ಪ್ರಾರಂಭವಾಗುವ ಸಾಮಾನ್ಯ web3 ಪ್ರಕ್ರಿಯೆಗಿಂತ ಇದು ಒಂದು ಅರ್ಥಪೂರ್ಣ ವ್ಯತ್ಯಾಸವಾಗಿದೆ. ಒಂದು ಸಾರ್ವಜನಿಕ ವೆಬ್‌ಸೈಟ್ ಅನ್ನು ಓದುವುದು ಹೇಗೆ ಅನುಮತಿಯಿಲ್ಲದ ಪ್ರಕ್ರಿಯೆಯೋ (permissionless), ಅದೇ ರೀತಿ Midnight ನಲ್ಲಿ ಐಡೆಂಟಿಟಿಯನ್ನು ಓದುವುದು ಕೂಡ ಅನುಮತಿಯಿಲ್ಲದ ಪ್ರಕ್ರಿಯೆಯಾಗಿದೆ.

ನಿಜವಾದ ಸಾರಾಂಶ

ಈ ವೀವರ್ ಅನ್ನು ನಿರ್ಮಿಸುವುದು ನನಗೆ ನೆನಪಿಸಿತು ಏನೆಂದರೆ, ಬ್ಲಾಕ್‌ಚೈನ್ ಅಭಿವೃದ್ಧಿಯ ಅತ್ಯಂತ ಕಷ್ಟದ ಭಾಗವು ಬ್ಲಾಕ್‌ಚೈನ್ ಆಗಿರುವುದಿಲ್ಲ. Midnight ಈಗಾಗಲೇ ಕಷ್ಟದ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಿದೆ: ಯಾವುದೇ ಕೇಂದ್ರ ಡೇಟಾಬೇಸ್ ಇಲ್ಲದೆ ಜನರು ತಮ್ಮ ಹೆಸರು ಮತ್ತು ಪ್ರೊಫೈಲ್ ಅನ್ನು ಹೊಂದಲು ಅವಕಾಶ ಮಾಡಿಕೊಡುವುದು. ಒಬ್ಬ ಬಿಲ್ಡರ್ ದೃಷ್ಟಿಕೋನದಿಂದ ಹೇಳುವುದಾದರೆ, ಕಷ್ಟದ ಭಾಗವೆಂದರೆ ನಾನು ಯಾವ ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ಬಳಸುತ್ತಿದ್ದೇನೆ ಎಂಬುದನ್ನು ನೆನಪಿಟ್ಟುಕೊಳ್ಳುವುದು ಮತ್ತು ಡೇಟಾ ಟೈಪ್‌ಗಳನ್ನು ಕ್ಲೀನ್ ಮಾಡಲು ಒಂದು ಹೆಲ್ಪರ್ ಫಂಕ್ಷನ್ ಬರೆಯುವುದು.

ಈ ಪ್ರೊಟೊಕಾಲ್ ನಿಮಗೆ ಪೋರ್ಟಬಲ್ ಐಡೆಂಟಿಟಿಯನ್ನು ನೀಡುತ್ತದೆ. ಒಬ್ಬ ಡೆವಲಪರ್ ಆಗಿ ನಿಮ್ಮ ಕೆಲಸವೆಂದರೆ ಅದನ್ನು ಸರಿಯಾಗಿ ಓದುವುದು ಮತ್ತು ಬಳಕೆದಾರರ ಹಾದಿಗೆ ಅಡ್ಡಿಯಾಗದೆ ಇರುವುದು. ಆರ್ಕಿಟೆಕ್ಚರ್ ಅನ್ನು ಸರಳವಾಗಿಡಿ, ಚೈನ್-ಫೇಸಿಂಗ್ ಲಾಜಿಕ್ ಅನ್ನು UI ನಿಂದ ಪ್ರತ್ಯೇಕಿಸಿ ಮತ್ತು ಪಬ್ಲಿಕ್ ರೀಡ್‌ಗಳನ್ನು ಅವುಗಳಂತೆಯೇ ಪರಿಗಣಿಸಿ: ಅಂದರೆ ಡಿಸ್ಟ್ರಿಬ್ಯೂಟೆಡ್ ಲೆಡ್ಜರ್‌ನಲ್ಲಿರುವ ಸಾಮಾನ್ಯ ಡೇಟಾಬೇಸ್ ಕ್ವೇರಿಗಳು ಎಂದು ಭಾವಿಸಿ.

ನೀವು ಕೋಡ್ ನೋಡಲು ಅಥವಾ ಅದನ್ನು ಸ್ವತಃ ರನ್ ಮಾಡಲು ಬಯಸಿದರೆ, ಸಂಪೂರ್ಣ ಸೋರ್ಸ್ https://github.com/tomiin/midnames-profile-viewer ನಲ್ಲಿ ಲಭ್ಯವಿದೆ.