-
Notifications
You must be signed in to change notification settings - Fork 17
add records resolution #1974
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
add records resolution #1974
Changes from 29 commits
eae25f6
bbf391c
e8653a4
6ff2930
713f1ee
319a99d
32f53c8
09b1435
7668d50
e1e5680
2e00efe
c88dde2
380dadf
4fef571
cf7cf01
b1232ab
bf275b9
cbdca11
8acc0b2
60d2793
0550de5
7c80a61
caa8f76
ab2b849
5b0b1d2
4e94c06
f5bacdd
c5330f0
6f50a9d
a0008ea
c5d7818
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| --- | ||
| "ensapi": patch | ||
| --- | ||
|
|
||
| Changes related to **Omnigraph**: | ||
|
|
||
| - add `Domain.records` with raw records resolution (`ResolvedRawTextRecord` for text record values) | ||
| - add `Account.primaryName(by: PrimaryNameByInput!)` and `Account.primaryNames(where: AccountPrimaryNamesWhereInput!)`. Primary name lookups accept `coinType` or `chain` (singular) and `coinTypes` or `chains` (plural, `@oneOf`); `ENSIP19Chain` includes `DEFAULT`; `PrimaryNameRecord.name` is a `CanonicalName` with `interpreted` and `beautified` | ||
| - add `UID` cache keys on `ResolvedRecords` (keyed by resolution `InterpretedName`) for graphcache normalization across queries | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. internal, no need to include |
||
| - add types-only `Domain.profile` and shared `DomainProfile` preview types (`ProfileAvatar`, `ProfileBanner`, `ProfileWebsite`, `ProfileAddresses`, `ProfileSocials`, etc.). Profile resolution is not wired yet; subfields return null | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. internal, no need to include |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,45 @@ | ||
| import type { Duration } from "enssdk"; | ||
|
|
||
| import { | ||
| hasOmnigraphApiConfigSupport, | ||
| hasOmnigraphApiIndexingStatusSupport, | ||
| } from "@ensnode/ensnode-sdk"; | ||
|
|
||
| import di from "@/di"; | ||
| import { errorResponse } from "@/lib/handlers/error-response"; | ||
| import { createApp } from "@/lib/hono-factory"; | ||
| import { canAccelerateMiddleware } from "@/middleware/can-accelerate.middleware"; | ||
| import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware"; | ||
| import { makeIsRealtimeMiddleware } from "@/middleware/is-realtime.middleware"; | ||
|
|
||
| /** | ||
| * The maximum distance (in seconds) from the current time to the latest indexed block | ||
| * for a chain to be considered "realtime" and thus eligible for protocol acceleration. | ||
| */ | ||
| const MAX_REALTIME_DISTANCE_TO_ACCELERATE: Duration = 600; // 10 minutes | ||
|
|
||
| const app = createApp({ middlewares: [indexingStatusMiddleware] }); | ||
| const app = createApp({ | ||
| middlewares: [ | ||
| indexingStatusMiddleware, | ||
| makeIsRealtimeMiddleware("omnigraph-api", MAX_REALTIME_DISTANCE_TO_ACCELERATE), | ||
| canAccelerateMiddleware, | ||
| ], | ||
| }); | ||
|
|
||
| app.use(async (c, next) => { | ||
| const configPrerequisite = hasOmnigraphApiConfigSupport(di.context.stackInfo.ensIndexer); | ||
| // 503 if Omnigraph API is not available due to config prerequisites not met | ||
| if (!configPrerequisite.supported) { | ||
| return c.text(`Service Unavailable: ${configPrerequisite.reason}`, 503); | ||
| return errorResponse(c, `Service Unavailable: ${configPrerequisite.reason}`, 503); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good fix
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, this should probably be a graphql error format since this is a graphql endpoint, but we can think about that later |
||
| } | ||
|
|
||
| // 503 if indexing status snapshot is not available yet | ||
| if (c.var.indexingStatus instanceof Error) { | ||
| return c.text(`Service Unavailable: Indexing Status Snapshot is not available yet`, 503); | ||
| return errorResponse( | ||
| c, | ||
| "Service Unavailable: Indexing Status Snapshot is not available yet", | ||
| 503, | ||
| ); | ||
| } | ||
|
|
||
| // 503 if omnigraph API not available due to indexing status prerequisites not met | ||
|
|
@@ -27,7 +48,7 @@ app.use(async (c, next) => { | |
| ); | ||
|
|
||
| if (!indexingStatusPrerequisite.supported) { | ||
| return c.text(`Service Unavailable: ${indexingStatusPrerequisite.reason}`, 503); | ||
| return errorResponse(c, `Service Unavailable: ${indexingStatusPrerequisite.reason}`, 503); | ||
| } | ||
|
|
||
| await next(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,16 @@ | ||
| import { SpanStatusCode, trace } from "@opentelemetry/api"; | ||
| import { coinTypeReverseLabel, evmChainIdToCoinType, reverseName } from "enssdk"; | ||
| import { | ||
| type Address, | ||
| type ChainId, | ||
| type CoinType, | ||
| coinTypeReverseLabel, | ||
| evmChainIdToCoinType, | ||
| reverseName, | ||
| } from "enssdk"; | ||
| import { isAddress, isAddressEqual } from "viem"; | ||
|
|
||
| import { | ||
| type ResolverRecordsSelection, | ||
| type ReverseResolutionArgs, | ||
| ReverseResolutionProtocolStep, | ||
| type ReverseResolutionResult, | ||
| TraceableENSProtocol, | ||
|
|
@@ -24,45 +30,45 @@ export const REVERSE_RESOLUTION_SELECTION = { | |
|
|
||
| const tracer = trace.getTracer("reverse-resolution"); | ||
|
|
||
| type ReverseResolutionOptions = Parameters<typeof resolveForward>[2]; | ||
|
|
||
| /** | ||
| * Implements ENS Reverse Resolution, including support for ENSIP-19 L2 Primary Names. | ||
| * Implements ENS Reverse Resolution for a specific coin type, including ENSIP-19 L2 Primary Names. | ||
| * | ||
| * @see https://docs.ens.domains/ensip/19/#algorithm | ||
| * | ||
| * The DEFAULT_EVM_CHAIN_ID (0) is a valid chainId in this context. | ||
| * | ||
| * @param address the adddress whose Primary Name to resolve | ||
| * @param chainId the chainId within which to resolve the address' Primary Name | ||
| * @param coinType the coinType within which to resolve the address' Primary Name | ||
| * @param options Optional settings | ||
| * @param options.accelerate Whether to accelerate resolution (default: true) | ||
| * @param options.canAccelerate Whether acceleration is currently possible (default: false) | ||
| */ | ||
| export async function resolveReverse( | ||
| address: ReverseResolutionArgs["address"], | ||
| chainId: ReverseResolutionArgs["chainId"], | ||
| options: Parameters<typeof resolveForward>[2], | ||
| export async function resolveReverseByCoinType( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah just call this |
||
| address: Address, | ||
| coinType: CoinType, | ||
| options: ReverseResolutionOptions, | ||
| ): Promise<ReverseResolutionResult> { | ||
| const { accelerate = true } = options; | ||
|
|
||
| // trace for external consumers | ||
| return withProtocolStep( | ||
| TraceableENSProtocol.ReverseResolution, | ||
| ReverseResolutionProtocolStep.Operation, | ||
| { address, chainId, accelerate }, | ||
| { address, coinType, accelerate }, | ||
| (protocolTracingSpan) => | ||
| // trace for internal metrics | ||
| withActiveSpanAsync( | ||
| tracer, | ||
| `resolveReverse(${address}, chainId: ${chainId})`, | ||
| { address, chainId, accelerate }, | ||
| `resolveReverseByCoinType(${address}, coinType: ${coinType})`, | ||
| { address, coinType, accelerate }, | ||
| async (span) => { | ||
| ///////////////////////////////////////////////////////// | ||
| // Reverse Resolution | ||
| // https://docs.ens.domains/ensip/19/#algorithm | ||
| ///////////////////////////////////////////////////////// | ||
|
|
||
| // Steps 1-3 — Resolve coinType-specific name record | ||
| const coinType = evmChainIdToCoinType(chainId); | ||
| const _reverseName = reverseName(address, coinType); | ||
| const { name } = await withProtocolStep( | ||
| TraceableENSProtocol.ReverseResolution, | ||
|
|
@@ -173,3 +179,24 @@ export async function resolveReverse( | |
| ), | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Implements ENS Reverse Resolution, including support for ENSIP-19 L2 Primary Names. | ||
| * | ||
| * @see https://docs.ens.domains/ensip/19/#algorithm | ||
| * | ||
| * The DEFAULT_EVM_CHAIN_ID (0) is a valid chainId in this context. | ||
| * | ||
| * @param address the adddress whose Primary Name to resolve | ||
| * @param chainId the chainId within which to resolve the address' Primary Name | ||
| * @param options Optional settings | ||
| * @param options.accelerate Whether to accelerate resolution (default: true) | ||
| * @param options.canAccelerate Whether acceleration is currently possible (default: false) | ||
| */ | ||
| export async function resolveReverse( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need for this function at all, from the perspective of the reverse resolution module, it only needs to know about coin types. |
||
| address: Address, | ||
| chainId: ChainId, | ||
| options: ReverseResolutionOptions, | ||
| ): Promise<ReverseResolutionResult> { | ||
| return resolveReverseByCoinType(address, evmChainIdToCoinType(chainId), options); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InterpretedName