Implementation

Step 1: Architecture design

First, we need to think about our architecture and design it. In our case it is a very simple project so the architecture could be something like this:

Figure 1 — Decentralized DNS (domain name system) Architecture

Step 2: Architecture preparation

There are already smart contracts for the safe math operations, ownership logic and destruction logic provided from OpenZeppelin, that have passed multiple security audits, so we don’t need to reinvent the wheel.

For the math operations we are going to use SafeMath library, which looks like this:

SafeMath.sol — Safe Mathematical operations in Solidity

For the ownership and destruction logic we will again use security audited and proven to work contracts from the openzeppelin-solidity Github repository and then proceed with the implementation of our own DDNS.

Ownable.sol — Ownership logic solidity

Destructible.sol — Smart contract lifecycle logic solidity

Lastly our main contract where we will put our logic for the decentralized domain name system (DDNS):

It inherits the Destructible.sol contract which itself inherits the ownership logic from the Ownable.sol contract and we are good to go.

The directory tree of our project could be looking like this at this point:

Figure 2 — Project structure for Decentralized Domain Name System

Step 3: Defining struct types, function modifiers, and state variables

Starting with the structures — structs are custom defined types that can group several variables. In our case, we will make some things easier by creating structures for them.

So, as we all know every problem has lots of different approaches to be solved, and I challenge you to try solving this one yourself and not trust mine as the “one and only solution”.

Structs

We are defining the DomainDetails structure which has the following properties:

bytes name — the domain name stored as bytes

bytes12 topLevel — the TLD of the domain

address owner — address of the owner

bytes15 ip — IP that is related to the domain name

uint expires — expiring date of the domain.

DomainDetails Structure for the DDNS implementation

Second we are defining the Receipt structure — which is something we should provide the user according to the project requirements we’ve set in the beginning. It has the following properties :

uint amountPaidWei — the price that was paid in this transaction, stored as the amount of wei (the smallest part of ether)

uint timestamp — the time when this receipt was issued

uint expires — expiring time

Receipt structure for the DDNS implementation

Modifiers

Modifiers can be used to easily change the behavior of functions. For example, they can automatically check a condition prior to executing the function. Modifiers are inheritable properties of contracts and may be overridden by derived contracts.

First modifier that we are going to implement is an isAvailable modifier, which we will be using to check whether a certain domain name is available to be bought.

The next thing the collectDomainNamePayments modifier that we are going to use as the way for faster check if the user provided the right amount of money for the payment.

collectDomainNamePayment modifier for the DDNS implementation

We need a modifier which we will use for checking whether the transaction initiator (msg.sender) is the owner of the certain domain — isDomainOwner.

And lastly, we need another two modifiers isDomainNameLengthAllowed and isTopLevelLengthAllowed for checking if the length of the provided domain name or TLD is allowed respectively.

isDomainNameLengthAllowed modifier

isTopLevelLengthAllowed modifier

State variables and constants

We are going to add some constants which names speak for what they are actually used for:

Constants used in our DDNS smart contract

and the state variables where we are going to store the domain names, payment receipts:

State variables for storing our data in the DDNS

Events

Events in Solidity give an abstraction on top of EVM’s (Ethereum Virtual Machine) logging functionality. An application (e.g. our UI) can subscribe to an event and listen for this events.

Events are defined with a number of parameters and their type. When an event is fired, its arguments are stored in the transaction’s log.

Notice the indexed attribute — in Solidity, you can add up to 3 indexed parameters for an event, which will add them to a special structure called “topic”.

We will get to this point in part 2 when we create the UI for the dApp.

For now, let us just add an event for every action that we are taking on our smart contract. That would be logging that a certain domain name was registered, also log if a domain was renewed. We will add an event for logging domain edits and transfers of a domain ownership. Lastly, we log the money operations and receipt issuing.

Defined events for the DDNS project implementations

Step 4: Implementing functions

And now let’s get to the interesting part …

First, we have to implement some functions that are going to help us with our logic, since the logic we’ve been following so far is:

As we know on the internet we could have domain names that are the same and only the TLD could be different (e.g. hack .bg and hack .com )

and ) We need to have a unique id for each domain name, combined with its TLD.

for each domain name, combined with its TLD. Solidity is bad with string manipulation