借助TheGraph 查询ENS信息

关于ENS (以太坊域名服务)

ENS 全称是 Ethereum Name Service,它是一个建立在以太坊区块链上的去中心化域名系统。

ENS 在 Web3 领域发挥着重要作用,主要有以下几个方面:

  1. 可读性更好的地址:

    • ENS 允许用户将复杂的以太坊地址(如 0x12345...) 映射为更简单易记的域名。
    • 这极大地提高了用户体验,让区块链的使用更加友好。
  2. 统一的身份标识:

    • ENS 域名可以用作用户在 Web3 生态中的唯一标识。
    • 用户可以将自己的钱包地址、social media账号等信息关联到ENS域名上。
  3. 去中心化的域名系统:

    • ENS 是建立在以太坊区块链之上的,不受任何中心化机构的控制。
    • 域名所有权通过区块链交易来管理,保证了所有权的去中心化。
  4. 支持多种应用场景:

    • ENS 域名可以用于支付、登录、数据存储等各种 Web3 应用场景。
    • 开发者可以在自己的 dApp 中集成 ENS 功能。
  5. 可编程性和可扩展性:

    • 作为一个基础设施,ENS 提供了丰富的API和SDK,方便开发者集成和扩展。
    • 未来 ENS 还可能支持更多类型的域名资源,如数据存储、身份认证等。

总ENS 是 Web3 生态中重要的一环,它在提高用户体验、统一身份标识等方面发挥着关键作用。

ENS(以太坊域名服务)可以认为是web3的DNS...DNS是将域名和IP地址做一个映射,而ENS是把域名和比IP地址更复杂冗长的钱包地址做一个映射

可以在 https://app.ens.domains/ 注册

折算后大概几十块人民币,和普通域名价格差不多

页面信息可以在这里查到: https://app.ens.domains/vitalik.eth

什么是以太坊域名服务 (ENS)?

比较著名的一个批量注册工具的ENS 成交榜,看得出比较好的"靓号"价格不菲...

关于TheGraph

TheGraph 可以说是 Web3 应用开发的基础设施之一,极大地提高了区块链数据的可访问性和可用性。

TheGraph 是一个去中心化的查询协议,在 Web3 领域扮演着非常重要的角色。主要用于索引和查询区块链数据。TheGraph 可以帮助用户做以下几件事:

  1. 索引区块链数据:

    • TheGraph 会收集和处理区块链上产生的各种数据,包括交易记录、合约事件等。
    • 通过定义 GraphQL 查询接口,开发者可以高效地查询和获取所需的数据。
  2. 为 dApp 提供数据查询服务:

    • dApp 开发者可以利用 TheGraph 提供的索引数据,构建出更丰富的用户体验。
    • 不需要自己处理复杂的区块链数据查询逻辑,大大降低了开发难度。
  3. 构建去中心化的数据市场:

    • TheGraph 网络由一群索引者(Indexers)组成,他们负责处理数据并提供查询服务。
    • Indexers可以获得来自 dApp 开发者的查询费用,形成一个去中心化的数据市场。
  4. 提高数据可靠性和安全性:

    • 由于 TheGraph 是建立在区块链之上的,数据查询过程是透明、可验证的。
    • 这大大提高了数据的可靠性和安全性,避免了单点故障问题。

如何使用TheGraph查询ENS信息?

以下是使用Go语言通过The Graph查询ENS信息的代码:

go 复制代码
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

const GraphQLEndpoint = "https://api.thegraph.com/subgraphs/name/ensdomains/ens"

type GraphQLRequest struct {
    Query     string                 `json:"query"`
    Variables map[string]interface{} `json:"variables"`
}

type GraphQLResponse struct {
    Data struct {
        Domains []struct {
            ID              string `json:"id"`
            Name            string `json:"name"`
            LabelName       string `json:"labelName"`
            ResolvedAddress struct {
                ID string `json:"id"`
            } `json:"resolvedAddress"`
            Owner struct {
                ID string `json:"id"`
            } `json:"owner"`
            Resolver struct {
                Address string `json:"address"`
            } `json:"resolver"`
            TTL       string `json:"ttl"`
            CreatedAt string `json:"createdAt"`
        } `json:"domains"`
    } `json:"data"`
}

func queryENS(domainName string) (*GraphQLResponse, error) {
    query := `
    query ($name: String!) {
        domains(where: { name: $name }) {
            id
            name
            labelName
            resolvedAddress { id }
            owner { id }
            resolver { address }
            ttl
            createdAt
        }
    }
    `

    variables := map[string]interface{}{
        "name": domainName,
    }

    requestBody, err := json.Marshal(GraphQLRequest{Query: query, Variables: variables})
    if err != nil {
        return nil, err
    }

    resp, err := http.Post(GraphQLEndpoint, "application/json", bytes.NewBuffer(requestBody))
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var graphQLResponse GraphQLResponse
    err = json.Unmarshal(body, &graphQLResponse)
    if err != nil {
        return nil, err
    }

    return &graphQLResponse, nil
}

func main() {
    domainName := "vitalik.eth"
    result, err := queryENS(domainName)
    if err != nil {
        fmt.Printf("Error querying ENS: %v\n", err)
        return
    }

   fmt.Println()
	fmt.Println("result.Data.Domains 长度为:", len(result.Data.Domains))

    if len(result.Data.Domains) > 0 {
        domain := result.Data.Domains[0]
        fmt.Printf("Domain Name: %s\n", domain.Name)
        fmt.Printf("Owner: %s\n", domain.Owner.ID)
        if domain.ResolvedAddress.ID != "" {
            fmt.Printf("Resolved Address: %s\n", domain.ResolvedAddress.ID)
        } else {
            fmt.Println("Resolved Address: Not set")
        }
        createdAt, _ := time.Parse(time.RFC3339, domain.CreatedAt)
        fmt.Printf("Created At: %s\n", createdAt.Format(time.RFC3339))
    } else {
        fmt.Println("Domain not found")
    }
}

这个Go程序执行以下操作:

  1. 定义了必要的结构体来表示GraphQL请求和响应。

  2. 实现了queryENS函数,该函数构造GraphQL查询,发送HTTP POST请求到The Graph的API端点,并解析响应。

  3. main函数中,我们使用"vitalik.eth"作为示例域名进行查询。

  4. 程序打印出查询结果,包括域名、所有者地址、解析地址(如果设置了的话)和创建时间。

可以查到数据

但请求次数稍微一多,就会限流:

shell 复制代码
{"message":"Rate-limit on ensdomains/ens community key exceeded. Try again later or go to https://thegraph.com/studio to create your own API key. Find the ensdomains/ens Graph Network Subgraph here: https://thegraph.com/explorer/subgraphs/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH"}

解决方案:

创建自己的 API 密钥:

    1. 如错误消息所示,可以在 https://thegraph.com/studio 创建自己的 API 密钥。这将有更高的查询频率限制 (免费的API key,每个月可以进行10万次查询)
    1. 使用 Graph Network:错误消息提供了 ENS 子图在 Graph Network 上的链接。可以直接使用这个网络版本的子图。

我申请了一个API key,类似 e65d654167ba349f029f0exxxxxxxxxx

根据文档,以及该子图主页的提示,修改代码如下:

go 复制代码
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
)


const GraphQLEndpoint = "https://gateway-arbitrum.network.thegraph.com/api/e65d654167ba349f029f0exxxxxxxxxx/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH"

type GraphQLRequest struct {
	Query     string                 `json:"query"`
	Variables map[string]interface{} `json:"variables"`
}

type GraphQLResponse struct {
	Data struct {
		Domains []struct {
			ID              string `json:"id"`
			Name            string `json:"name"`
			LabelName       string `json:"labelName"`
			ResolvedAddress struct {
				ID string `json:"id"`
			} `json:"resolvedAddress"`
			Owner struct {
				ID string `json:"id"`
			} `json:"owner"`
			Resolver struct {
				Address string `json:"address"`
			} `json:"resolver"`
			TTL       string `json:"ttl"`
			CreatedAt string `json:"createdAt"`
		} `json:"domains"`
	} `json:"data"`
}

func queryENS(domainName string) (*GraphQLResponse, error) {
	query := `
    query ($name: String!) {
        domains(where: { name: $name }) {
            id
            name
            labelName
            resolvedAddress { id }
            owner { id }
            resolver { address }
            ttl
            createdAt
        }
    }
    `

	variables := map[string]interface{}{
		"name": domainName,
	}

	requestBody, err := json.Marshal(GraphQLRequest{Query: query, Variables: variables})
	if err != nil {
		return nil, err
	}

	resp, err := http.Post(GraphQLEndpoint, "application/json", bytes.NewBuffer(requestBody)) 

	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// 打印原始响应
	fmt.Println("Raw response:", string(body))

	var graphQLResponse GraphQLResponse
	err = json.Unmarshal(body, &graphQLResponse)
	if err != nil {
		return nil, err
	}

	return &graphQLResponse, nil
}

func main() {
	domainName := "vitalik.eth"
	result, err := queryENS(domainName)
	if err != nil {
		fmt.Printf("Error querying ENS: %v\n", err)
		return
	}

	fmt.Println()
	fmt.Println("result.Data.Domains 长度为:", len(result.Data.Domains))

	if len(result.Data.Domains) > 0 {
		domain := result.Data.Domains[0]
		fmt.Printf("Domain Name: %s\n", domain.Name)
		fmt.Printf("Owner: %s\n", domain.Owner.ID)
		if domain.ResolvedAddress.ID != "" {
			fmt.Printf("Resolved Address: %s\n", domain.ResolvedAddress.ID)
		} else {
			fmt.Println("Resolved Address: Not set")
		}

		fmt.Println("domain.CreatedAt is:", domain.CreatedAt)

		intCreateAt, _ := strconv.Atoi(domain.CreatedAt)
		createdAt := time.Unix(int64(intCreateAt), 0).Format(time.DateTime)
		fmt.Printf("Created At: %s\n", createdAt)
	} else {
		fmt.Println("Domain not found")
	}
}

返回值为:

shell 复制代码
Raw response: {"data":{"domains":[{"createdAt":"1497775154","id":"0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835","labelName":"vitalik","name":"vitalik.eth","owner":{"id":"0xd8da6bf26964af9d7eed9e03e53415d37aa96045"},"resolvedAddress":{"id":"0xd8da6bf26964af9d7eed9e03e53415d37aa96045"},"resolver":{"address":"0x231b0ee14048e9dccd1d247744d114a4eb5e8e63"},"ttl":null}]}}

result.Data.Domains 长度为: 1
Domain Name: vitalik.eth
Owner: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045
Resolved Address: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045
domain.CreatedAt is: 1497775154
Created At: 2017-06-18 16:39:14
相关推荐
web3探路者3 小时前
深入探索Solana链上的Meme生态:创新、潜力与挑战#区块链开发#dapp开发
web3·区块链·团队开发·dapp开发·区块链技术·链游开发·交易所开发
加密新世界16 小时前
指南: 如何在 MEV 项目中使用 Yul
区块链
MavenTalk2 天前
solana链上智能合约开发案例一则
rust·区块链·智能合约·dapp·solana
kejijianwen3 天前
Algen的跨链互操作性:增强区块链连接性
运维·centos·区块链
Sui_Network4 天前
World Wide Walrus:下一代数据存储协议
大数据·人工智能·web3·去中心化·区块链
Huazzi.4 天前
区块链中的wasm合约是什么?
区块链·wasm
一水鉴天4 天前
智能工厂的设计软件 为了监管控一体化的全能Supervisor 的监督学习 之 序6 进化论及科学的信息技术创新:分布式账本/区块链/智能合约
开发语言·人工智能·学习·区块链·智能合约·分布式账本
电报号dapp1194 天前
TON商城与Telegram App:生态融合与去中心化未来的精彩碰撞
去中心化·区块链
加密新世界4 天前
掌控 Solidity:事件日志、继承和接口的深度解析
区块链
MavenTalk4 天前
两大新兴开发语言大比拼:Move PK Rust
开发语言·后端·rust·区块链