借助TheGraph 查询ENS信息

news2024/12/23 12:57:30

关于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信息的代码:

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


可以查到数据

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

{"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

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


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")
	}
}

返回值为:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1859947.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

KUBIKOS - Animated Cube Mini BIRDS(卡通立方体鸟类)

软件包中添加了对通用渲染管线 (URP) 的支持! KUBIKOS - 动画立方体迷你鸟是17种不同的可爱低多边形移动友好鸟的集合!每只都有自己的动画集。 完美收藏你的游戏! +17种不同的动物! + 低多边形(400~900个三角形) + 操纵和动画! + 4096x4096 纹理图集 + Mecanim 准备就绪…

生命在于学习——Python人工智能原理(4.3)

三、Python的数据类型 3.1 python的基本数据类型 3.1.4 布尔值(bool) 在Python中,布尔值是表示真或假的数据类型,有两个取值,True和False,布尔值常用于控制流程、条件判断和逻辑运算,本质上来…

项目实训-接口测试(十八)

项目实训-后端接口测试(十八) 文章目录 项目实训-后端接口测试(十八)1.概述2.测试对象3.测试一4.测试二 1.概述 本篇博客将记录我在后端接口测试中的工作。 2.测试对象 3.测试一 这段代码是一个单元测试方法,用于验证…

idea 开发工具properties文件中的中文不显示

用idea打开一个项目,配置文件propertise中的中文都不展示,如图: 可修改idea配置让中文显示: 勾选箭头指向的框即可,点击应用保存,重新打开配置文件,显示正常

篮球联盟管理系统

管理员账户功能包括:系统首页,个人中心,管理员管理,球员管理,用户管理,球队管理,论坛管理,篮球资讯管理,基础数据管理 前台账户功能包括:系统首页&#xff0…

Cell2Sentence:为LLM传输生物语言

像GPT这样的LLM在自然语言任务上表现出了令人印象深刻的性能。这里介绍一种新的方法,通过将基因表达数据表示为文本,让这些预训练的模型直接适应生物背景,特别是单细胞转录组学。具体来说,Cell2Sentence将每个细胞的基因表达谱转换…

前端架构(含演进历程、设计内容、AI辅助设计、架构演进历程)

前端架构的演进历程 前端架构师的必要条件 全面的技术底蕴全局观(近期 远期)业务要有非常深刻的理解沟通协调能力和团队意识深刻理解前端架构的原则和模式 前端架构的设计内容 技术选型(库、工具、标准规范、性能、安全、扩展性 )设计模式及代码组织(模…

ADS SIPro使用技巧之RapidScan-Z0

PCB走线的阻抗对每个网络的信号完整性至关重要,但是,验证每个信号是不切实际的,尤其对于设计复杂度很高的产品而言,设计者的有限精力只能用于关注关键的设计点,这一过程往往会造成一些设计的疏忽从而导致错误。 ADS SI…

97. 交错字符串(leetcode)

97. 交错字符串(leetcode) 题目描述 给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串: s s1 …

图书管理系统(详解版 附源码)

目录 项目分析 实现页面 功能描述 页面预览 准备工作 数据准备 创建数据库 用户表 创建项目 导入前端页面 测试前端页面 后端代码实现 项目公共模块 实体类 公共层 统一结果返回 统一异常处理 业务实现 持久层 用户登录 用户注册 密码加密验证 添加图书…

串口小工具(来源网络,源码修改)

从CSDN 中的一位博主的分享做了一些修改 QtSerial 的配和更稳定些 信号和槽 … … 更不容易崩 # This Python file uses the following encoding: utf-8 import sys import timefrom PySide6.QtGui import QIcon, QTextCursor from PySide6.QtWidgets import QApplication, QWi…

【PyQt5】一文向您详细介绍 layout.addWidget() 的作用

【PyQt5】一文向您详细介绍 layout.addWidget() 的作用 下滑即可查看博客内容 🌈 欢迎莅临我的个人主页 👈这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 博主简介:985高校的普通本…

el-dialog el-select适配移动端

一、el-dialog 2024.06.20今天我学习了如何对el-dialog弹窗适配移动端展示,效果如下: 代码如下: media screen and (min-width: 220px) and (max-width: 600px) {::v-deep .el-dialog {width: 95% !important;} } 二、el-select 代码如下…

技术革命背后的新功能发布:探索Facebook创新

随着技术的飞速发展和社交媒体的普及,Facebook作为全球最大的社交平台之一,不断推出新的功能和服务,以满足用户的需求和提升用户体验。这些新功能不仅仅是技术进步的体现,更是Facebook在竞争激烈的数字化时代中保持领先地位的关键…

CANFD每秒最多可以发送多少帧报文?CAN FD结构详解

我们知道CANFD比CAN拥有更长的数据长度(最长64字节),更高的波特率(8Mbps甚至更高)。那么波特率更高,数据更长的CANFD,一秒钟最高可以发送多少帧CANFD报文呢? 想知道问题的答案&#…

C++结构体内存对齐规则

背景介绍 最近在使用Java语言写一个Java客户端,对接一个C/C语言编写的Server时,采用TCP协议进行通信,在将C结构体序列化的输出流转换为Java结构体时,需要按照结构体每个字段对应的字节长度截取字节流转换为Java类型,遇…

2024国际数字能源展,推动全球能源产业转型升级和可持续发展

随着全球对能源安全和可持续发展的日益关注,数字能源技术作为推动能源革命的重要力量,正逐步成为国际能源领域的新热点。2023年6月29日至7月2日,深圳会展中心成功举办了全球首个以数字能源为主题的2023国际数字能源展,这一盛会的成…

ET实现游戏中邮件系统逻辑思路(服务端)

ET是一个游戏框架,用的编程语言是C#,游戏引擎是Unity,框架作者:熊猫 ET社区 在游戏中我们通常都会看到有邮件系统,邮件系统的作用有给玩家通知、发放奖励等 下面小编使用ET框架带大家看一下邮件系统的一种实现方…

新型基坑气膜:施工开挖的得力干将—轻空间

随着城市建设的加速推进,施工过程中的环境问题日益受到关注。新型基坑气膜以其卓越的防尘、降噪、节能和防火功能,成为施工开挖领域中的得力干将,极大地提升了绿色施工的水平。 基坑气膜的作用 基坑气膜在施工现场形成了一个完全封闭的作业空…

数据模型(models)

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 (1)在App中添加数据模型 在app1的models.py中添加如下代码: from django.db import models # 引入django.…