Skip to content

Instantly share code, notes, and snippets.

@nxt3d
Created March 28, 2023 23:42
Show Gist options
  • Save nxt3d/9d1eecd841f29fde885bc673604ee18d to your computer and use it in GitHub Desktop.
Save nxt3d/9d1eecd841f29fde885bc673604ee18d to your computer and use it in GitHub Desktop.
Solidity code to get the name hash of any ens name (It can be used in Remix).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract NameEncoder {
using BytesUtils for bytes;
function dnsEncodeName(
string memory name
) public pure returns (bytes memory dnsName, bytes32 node) {
uint8 labelLength = 0;
bytes memory bytesName = bytes(name);
uint256 length = bytesName.length;
dnsName = new bytes(length + 2);
node = 0;
if (length == 0) {
dnsName[0] = 0;
return (dnsName, node);
}
// use unchecked to save gas since we check for an underflow
// and we check for the length before the loop
unchecked {
for (uint256 i = length - 1; i >= 0; i--) {
if (bytesName[i] == ".") {
dnsName[i + 1] = bytes1(labelLength);
node = keccak256(
abi.encodePacked(
node,
bytesName.keccak(i + 1, labelLength)
)
);
labelLength = 0;
} else {
labelLength += 1;
dnsName[i + 1] = bytesName[i];
}
if (i == 0) {
break;
}
}
}
node = keccak256(
abi.encodePacked(node, bytesName.keccak(0, labelLength))
);
dnsName[0] = bytes1(labelLength);
return (dnsName, node);
}
}
library BytesUtils {
/*
* @dev Returns the keccak-256 hash of a byte range.
* @param self The byte string to hash.
* @param offset The position to start hashing at.
* @param len The number of bytes to hash.
* @return The hash of the byte range.
*/
function keccak(
bytes memory self,
uint256 offset,
uint256 len
) internal pure returns (bytes32 ret) {
require(offset + len <= self.length);
assembly {
ret := keccak256(add(add(self, 32), offset), len)
}
}
/**
* @dev Returns the ENS namehash of a DNS-encoded name.
* @param self The DNS-encoded name to hash.
* @param offset The offset at which to start hashing.
* @return The namehash of the name.
*/
function namehash(
bytes memory self,
uint256 offset
) internal pure returns (bytes32) {
(bytes32 labelhash, uint256 newOffset) = readLabel(self, offset);
if (labelhash == bytes32(0)) {
require(offset == self.length - 1, "namehash: Junk at end of name");
return bytes32(0);
}
return
keccak256(abi.encodePacked(namehash(self, newOffset), labelhash));
}
/**
* @dev Returns the keccak-256 hash of a DNS-encoded label, and the offset to the start of the next label.
* @param self The byte string to read a label from.
* @param idx The index to read a label at.
* @return labelhash The hash of the label at the specified index, or 0 if it is the last label.
* @return newIdx The index of the start of the next label.
*/
function readLabel(
bytes memory self,
uint256 idx
) internal pure returns (bytes32 labelhash, uint256 newIdx) {
require(idx < self.length, "readLabel: Index out of bounds");
uint256 len = uint256(uint8(self[idx]));
if (len > 0) {
labelhash = keccak(self, idx + 1, len);
} else {
labelhash = bytes32(0);
}
newIdx = idx + len + 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment