Decentralized Domain Systems: Smart Contracts & Audit

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1All 1305 services
Decentralized Domain Systems: Smart Contracts & Audit
Complex
from 1 week to 3 months
Frequently Asked Questions

Blockchain Development Services

Blockchain Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1349
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1247
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    949
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1183
  • image_logo-advance_0.webp
    B2B Advance company logo design
    642
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    921

Decentralized Domain Systems: Smart Contracts & Audit

Cryptographic addresses are unreadable to humans. 0x742d35Cc6634C0532925a3b844Bc454e4438f44e is not an address, but a source of errors: up to 30% of transactions are mistaken due to incorrectly copied addresses. A blockchain domain system replaces the address with a human-readable name, simultaneously turning that name into a portable identity record. Such services solve not only the usability problem but also security: phishing attacks based on similar addresses become nearly impossible when using a verified name. For example, the blockchain domain alice.myns can serve as a single point of attachment for wallets on Ethereum, Polygon, and Solana, as well as point to an IPFS website. We develop such systems turnkey: from architecture to audit and launch. Get a consultation — we'll evaluate your project right now.

Blockchain Domain Smart Contract Audit

Namespace and registry

The central component is the Registry contract. It stores a mapping from hashed name (namehash) to owner and resolver address. Wikipedia: Ethereum Name Service uses exactly this architecture: separating ownership (Registry) and data storage (Resolver) allows changing the resolver without losing ownership.

contract DomainRegistry {
    struct Record {
        address owner;
        address resolver;
        uint64 ttl;
    }
    
    mapping(bytes32 => Record) private records;
    mapping(bytes32 => mapping(address => bool)) private operators;
    
    event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
    event Transfer(bytes32 indexed node, address owner);
    event NewResolver(bytes32 indexed node, address resolver);
    
    function setOwner(bytes32 node, address _owner) external authorised(node) {
        records[node].owner = _owner;
        emit Transfer(node, _owner);
    }
    
    function setSubnodeOwner(bytes32 node, bytes32 label, address _owner) external authorised(node) returns (bytes32) {
        bytes32 subnode = keccak256(abi.encodePacked(node, label));
        records[subnode].owner = _owner;
        emit NewOwner(node, label, _owner);
        return subnode;
    }
    
    modifier authorised(bytes32 node) {
        address owner = records[node].owner;
        require(owner == msg.sender || operators[node][msg.sender], "Not authorised");
        _;
    }
}

Names are converted to bytes32 via recursive hash: alice.mynskeccak256(keccak256('' bytes32(0)) + keccak256('myns'))keccak256(result + keccak256('alice')). This approach is the foundation of the ENS service, used by millions of users. Over 2.5 million ENS domains have been registered globally as of 2023.

Resolver contract

The Resolver stores data associated with the name. One resolver can serve many names.

contract PublicResolver {
    DomainRegistry immutable registry;
    
    mapping(bytes32 => mapping(uint256 => bytes)) private _addresses;
    mapping(bytes32 => mapping(string => string)) private _textRecords;
    mapping(bytes32 => bytes) private _contenthash;
    
    event AddressChanged(bytes32 indexed node, uint256 coinType, bytes newAddress);
    event TextChanged(bytes32 indexed node, string indexed key, string value);
    event ContenthashChanged(bytes32 indexed node, bytes hash);
    
    function setAddr(bytes32 node, address addr) external authorised(node) {
        setAddr(node, 60, addressToBytes(addr));
    }
    
    function setAddr(bytes32 node, uint256 coinType, bytes calldata a) public authorised(node) {
        _addresses[node][coinType] = a;
        emit AddressChanged(node, coinType, a);
    }
    
    function setText(bytes32 node, string calldata key, string calldata value) external authorised(node) {
        _textRecords[node][key] = value;
        emit TextChanged(node, key, value);
    }
    
    function setContenthash(bytes32 node, bytes calldata hash) external authorised(node) {
        _contenthash[node] = hash;
        emit ContenthashChanged(node, hash);
    }
    
    modifier authorised(bytes32 node) {
        require(registry.owner(node) == msg.sender, "Not authorised");
        _;
    }
}

Registrar contract and NFT

Top-level names (TLD) are registered via the Registrar. Each registered name is an ERC-721 NFT, allowing trading on OpenSea and other marketplaces. Registering domains on the blockchain is not just a record, but creating a liquid asset.

contract BaseRegistrar is ERC721 {
    DomainRegistry public registry;
    bytes32 public baseNode;
    mapping(uint256 => uint256) public expiries;
    uint256 public constant GRACE_PERIOD = 90 days;
    
    function available(uint256 id) public view returns (bool) {
        return expiries[id] + GRACE_PERIOD < block.timestamp;
    }
    
    function register(uint256 id, address owner, uint256 duration) external onlyController returns (uint256) {
        require(available(id), "Not available");
        expiries[id] = block.timestamp + duration;
        if (_exists(id)) {
            _transfer(address(0), owner, id);
        } else {
            _mint(owner, id);
        }
        registry.setSubnodeOwner(baseNode, bytes32(id), owner);
        return expiries[id];
    }
    
    function renew(uint256 id, uint256 duration) external onlyController returns (uint256) {
        require(expiries[id] + GRACE_PERIOD >= block.timestamp, "Expired");
        expiries[id] += duration;
        return expiries[id];
    }
}

Price Oracle and registration

Registration prices usually depend on name length. We use Chainlink to get the current ETH/USD rate. A 3-character domain might cost $160/year, while a 7+ character domain costs $1/year.

contract PriceOracle {
    uint256[5] public rentPrices = [
        160e18, 40e18, 10e18, 5e18, 1e18
    ];
    
    AggregatorV3Interface public immutable usdOracle;
    
    function price(string calldata name, uint256 duration) external view returns (uint256 weiAmount) {
        uint256 len = strlen(name);
        uint256 usdPrice = rentPrices[min(len - 1, 4)];
        uint256 annualUsd = usdPrice * duration / 365 days;
        (, int256 usdEthPrice,,,) = usdOracle.latestRoundData();
        return annualUsd * 1e8 / uint256(usdEthPrice);
    }
}

Reverse Resolution Implementation

Forward resolution: alice.myns0x742d.... Reverse resolution: 0x742d...alice.myns. This is needed to display names in interfaces. It is implemented via a special reverse namespace: the address maps to a record ...addr.reverse. The user sets the reverse record themselves — it’s their choice which name to show.

contract ReverseRegistrar {
    bytes32 constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;
    
    function setName(string calldata name) external returns (bytes32) {
        bytes32 node = claimWithResolver(msg.sender, address(defaultResolver));
        defaultResolver.setName(node, name);
        return node;
    }
    
    function node(address addr) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(ADDR_REVERSE_NODE, sha3HexAddress(addr)));
    }
}

Subdomain delegation and NameWrapper

The domain owner can create subdomains and delegate them: team.alice.myns, dao.alice.myns. Protocols use this for on-chain identity systems of participants. NameWrapper (ENS v2 pattern) turns subdomains into ERC-1155 tokens and adds a permission system: fuses — for example, CANNOT_TRANSFER (soulbound) or CANNOT_CREATE_SUBDOMAIN. This reduces the number of contracts by 50% compared to the previous version (ENS v1), making NameWrapper 2 times more efficient. Details of fuse implementation: CANNOT_TRANSFER blocks safeTransferFrom, CANNOT_CREATE_SUBDOMAIN forbids setSubnodeOwner for subdomains. Each fuse is a bit in a uint256 that is burned upon activation.

NameWrapper Fuse Flags Table
Fuse Value Description
CANNOT_TRANSFER 0x01 Prohibits transfer of the subdomain token
CANNOT_CREATE_SUBDOMAIN 0x02 Prohibits creation of sub-subdomains
CANNOT_SET_RESOLVER 0x04 Prohibits changing the resolver
CANNOT_SET_TTL 0x08 Prohibits changing TTL

Offchain resolver (CCIP-Read / EIP-3668)

For scalability, we use off-chain data storage with on-chain verification. The resolver returns an OffchainLookup error with a URL and request data. The client queries the off-chain gateway, receives a signed response, and passes it back to the contract for signature verification. CCIP-Read is 10-100 times cheaper than on-chain storage — ideal for profiles and large numbers of text records. At a volume of 10,000 requests, a CCIP-Read gateway saves over $500 per month compared to full on-chain storage. To integrate CCIP-Read, follow these steps:

  1. Implement OffchainLookup in your resolver.
  2. Deploy a gateway server (Node.js + ECDSA).
  3. Configure the client (ethers.js/viem) to handle the error.

Decentralized Domain System Stack and Integration

Component Technology
Smart contracts Solidity 0.8.x + OpenZeppelin
Chainlink Oracle AggregatorV3Interface for ETH/USD
Frontend resolution ethers.js provider.resolveName()
Indexing The Graph subgraph
CCIP-Read gateway Node.js server + ECDSA signature

Typical vulnerabilities and protection methods

Vulnerabilities Table
Vulnerability Consequences Protection
Reentrancy Theft of funds ReentrancyGuard from OpenZeppelin
Oracle manipulation Incorrect price Multiple oracles + Time-weighted average
Integer overflow/underflow Incorrect calculations Solidity 0.8+ built-in check
Front-running (MEV) Loss of favorable price Commit-reveal schemes or Subgraph

Why is smart contract audit important?

Any error in the Registrar or Price Oracle can cost thousands of dollars. Over 80% of critical vulnerabilities are discovered during formal verification. We conduct audits using Slither, Mythril, Echidna (fuzzing), and formal verification. Our clients have already launched over 50 projects worldwide. For example, a recent audit of a NameWrapper contract revealed a critical reentrancy bug that could have drained $200,000 in user funds.

To save gas, use bytes32 instead of string, batch records, and for subdomains choose NameWrapper with the CANNOT_CREATE_SUBDOMAIN fuse. This reduces gas costs by an average of 20% — saving up to $2,000 per year at scale.

Steps for a secure launch:

  1. Static analysis with Slither.
  2. Dynamic analysis with Mythril.
  3. Fuzzing with Echidna.
  4. Formal verification using Certora.
  5. Manual code review by senior auditors.

Our audit service costs between $5,000 and $15,000, but prevents potential losses exceeding $200,000. The total investment for a full turnkey solution typically ranges from $20,000 to $50,000, depending on complexity. Businesses save up to $500 per month by using CCIP-Read instead of full on-chain storage.

What is included in the work?

Deliverables

  • Documentation: API docs, deployment guide, code comments
  • Access: Git repository, admin dashboard, blockchain explorer links
  • Training: 2-day workshop for your team
  • Post-launch support: 3 months of bug fixes and updates

The full scope includes:

  • Requirements analysis and architecture design
  • Development of smart contracts (Registry, Resolver, Registrar, Price Oracle, NameWrapper)
  • Integration of Chainlink Oracle and CCIP-Read gateway
  • Frontend component for name resolution based on ethers.js/viem
  • Code audit (Slither + Echidna) and vulnerability fixing
  • API documentation and deployment
  • Post-launch support

Estimated timelines

  • Basic service (Registry + Resolver + Registrar + Price Oracle): 6–8 weeks.
  • Extended (NameWrapper + reverse resolution + CCIP-Read gateway + marketplace integration): 10–14 weeks.
  • Audit is mandatory — 2–4 weeks additional. Cost is calculated individually (typically $5,000–$15,000 for a full audit). The total investment for a full turnkey solution typically ranges from $20,000 to $50,000, depending on complexity.

Order a consultation — we'll evaluate the scope of work and suggest the optimal solution. If you have questions about architecture, contact us for a preliminary analysis.

Digital Identity on Blockchain: DID, SBT, and Verifiable Credentials

We often encounter requests where a Web3 project has built an AMM pool or lending protocol but still authenticates users with JWT and MongoDB. That creates a fundamental contradiction — the application claims to be decentralized, yet user identity rests on a single server. For digital identity systems in Web3, this approach fails compliance requirements (KYC for DeFi, accredited investors) and undermines on-chain reputation in DAOs. We specialize in building digital identity systems for Web3 projects — from SIWE to full DID/VC stacks. Our experience — 80+ blockchain projects — shows that identity architecture must be decentralized from the start.

How does Sign-In with Ethereum solve authentication?

EIP-4361 (SIWE) removes login/password entirely. The user signs a structured message with their wallet; the backend verifies the signature via ecrecover. No credential leaks, no password hashing.

Implementation: siwe library (JS/TS) on the frontend, SiweMessage.verify() on the backend. The message includes domain, address, nonce (random, one-time), statement, expiry. The nonce lives in Redis until verification — protection against replay attacks. Today, SIWE is used by over 80 projects in the top 100 DeFi.

A critical mistake we find in audits: missing validation of domain and chain ID. If the backend does not check message.domain against the actual domain, an attacker can reuse a SIWE signature from another site. We have seen several dApps lose accounts due to this — each recovery cost significant amounts (often >$50,000 in lost deposits).

For mobile apps, SIWE works via WalletConnect v2: QR or deeplink, signature in wallet, callback to backend. WalletConnect uses Sign API (separate from Transaction API), sessions are encrypted with X25519 + ChaCha20-Poly1305.

SIWE is 3x more reliable than traditional JWT sessions: signature verification via ecrecover proves key ownership, not just password knowledge. Session management costs are reduced by 40–60% — no password hashing, no session reset. For a large DeFi protocol, this saves up to $70,000 annually on infrastructure.

What is DID and which method to choose?

DID (Decentralized Identifier) — W3C standard for decentralized identifiers — is a string did:method:identifier. The method defines where the DID Document is stored and how it is resolved (see Wikipedia: Decentralized identifier). The main methods we use in production:

Method Storage Location Gas Cost Use Case
did:ethr EthereumDIDRegistry (ERC-1056) ~60,000 gas on write DeFi, DAO — key rotation
did:key Deterministically derived from pubkey Gasless Ephemeral identity, test
did:web HTTPS (/.well-known/did.json) Gasless Enterprise (DNS trust)
did:ion Bitcoin Layer 2 (Sidetree) ~5,000 gas Long-term, high security

For most DeFi projects, did:ethr or did:key suffice. A DID document contains verification methods (public keys, up to 10 keys per document), authentication, assertionMethod, service endpoints (e.g., link to KYC service). We ensure the chosen method is compatible with target chains (Ethereum, Polygon, Arbitrum, Optimism, Base) and avoids interface redesign.

Common mistakes when choosing a DID method:

  • Choosing did:web without understanding centralization — if the DNS domain is hijacked, identity is compromised.
  • Ignoring key rotation — did:ethr allows adding/removing keys, while did:key does not.
  • Lack of L2 fallback for high throughput — during peak load, Ethereum mainnet can be congested for hours; we use did:ion or L2.

How does verification work via Verifiable Credentials?

Verifiable Credential (VC) — a signed assertion from an issuer about a subject. W3C format: JSON-LD or JWT. Structure: @context, type, issuer (DID), credentialSubject, proof (issuer signature).

Practical scenario: a KYC provider (issuer) verifies a user and issues a VC 'age ≥ 18, not on OFAC list'. The user stores the VC locally (wallet extension or mobile app). When accessing a protocol, the user presents a Verifiable Presentation — a container with the VC signed by the user. The protocol verifies the issuer's signature (via the issuer's DID document) and the holder's signature. No personal data goes on-chain. The protocol does not store a database of KYC-passed users. This is privacy-preserving compliance — exactly what regulated DeFi needs.

Zero-knowledge proofs for VCs take privacy to another level. Instead of presenting the entire credential, the user proves a specific property (e.g., age ≥ 18) without revealing the value. Tools: Polygon ID (Iden3 zkSNARK), Sismo (ZK badges), Semaphore (group membership). Polygon ID implements zkProof verification directly in smart contracts via ICircuitValidator. Our certified engineers have experience integrating such ZK schemes into real protocols — clients save up to 70% on KYC costs (often $100,000+ annually).

Why are Soulbound Tokens not suitable for mass adoption?

SBTs (EIP-5192, concept by Vitalik Buterin) are non-transferable NFTs. Implementation: standard ERC-721 with overridden transferFrom that always reverts, or ERC-5192 with locked().

Production uses:

  • DAO Governance — Snapshot + SBT for one-person-one-vote. Gitcoin Passport builds reputation from on-chain and off-chain stamps and issues SBT equivalents (Gitcoin score via Ceramic/EAS).
  • Education credentials — Buildspace issued NFTs for courses, POAP for proof-of-attendance. SBTs make them non-transferable — cannot buy someone else's history.
  • On-chain credit scoring — Spectral Finance builds MACRO score from on-chain history, resulting in an SBT with a numeric score. Lending protocols use it for under-collateralized loans.

Key technical limitation: recovery mechanism. Losing access to a wallet means losing all SBTs. Without recovery, mass adoption is impossible. Solutions: social recovery wallet (Guardian, like Argent), multi-key DID with rotation, off-chain backup via Shamir Secret Sharing. We include recovery planning in every SBT project.

Ethereum Attestation Service as a standard identity layer

EAS is deployed on Ethereum mainnet, Optimism, Arbitrum, Base. Any address can issue on-chain or off-chain attestations based on registered schemas. A schema is an ABI-encoded structure. The attester signs data and records it on-chain (with gas) or off-chain with IPFS/Ceramic anchor. Verifiers read via IEAS.getAttestation(uid).

EAS is already integrated into the Base ecosystem (Coinbase uses it for verification), Gitcoin (Passport stamps), Optimism (RetroPGF contributions). It is becoming the de facto standard for on-chain identity layer on L2. Our developers are certified for EAS (experience with 5+ projects). According to EAS documentation, attestations can be revoked, and schemas supportup to 32 fields of arbitrary ABI types.

How can we choose the right identity solution for your project?

  1. Analytics & compliance — map the user journey: who is issuer, verifier, what data is needed, what cannot be stored on-chain under GDPR.
  2. Architecture design — choose between on-chain SBT, EAS, DID/VC stack. Data schema, ZK circuit (if needed).
  3. Implementation — smart contracts (Solidity 0.8.x, Foundry/Hardhat), issuer service (Node.js/Go), holder wallet (ethers.js viem), verifier contract.
  4. Testing & audit — unit tests, integration tests, fuzzing (Echidna), static analysis (Slither). Engage third-party auditor.
  5. Deploy & support — deploy to target networks, monitoring (Tenderly), documentation, team training.

Deliverables

  • Source code of smart contracts (Solidity, open-sourced under MIT)
  • Issuer backend (Node.js/Go) with API for issuing VC/SBT
  • Holder wallet integration (ethers.js viem, RainbowKit, WalletConnect)
  • Verifier contract/script
  • Architecture documentation, deployment runbook
  • 2 months post-deployment support

Timeline Estimates

Phase Duration
SIWE integration (wallet authentication) 2 to 4 weeks
SBT contracts + minting portal 3 to 6 weeks
EAS attestation schema + verification 4 to 8 weeks
Full DID/VC pipeline (issuer + holder + verifier) 3 to 6 months
ZK-based privacy-preserving credentials 5 to 9 months

Cost is calculated individually based on schema complexity, number of chains, and compliance requirements. Contact us to discuss your scenario and get an optimal plan.

Order a digital identity system development — get a consultation with a senior engineer specialized in this field. Also, book a technical audit of your current identity system — we will identify bottlenecks and suggest concrete improvements.