From 8caf9136502aa86a03ffbec679274bb88f4aa3e3 Mon Sep 17 00:00:00 2001 From: b4rtaz Date: Tue, 4 Apr 2023 15:50:28 +0200 Subject: [PATCH] feat: resolveENSDomain. --- .changeset/dry-zebras-ring.md | 6 ++ .../common/evmUtils/src/operations/openapi.ts | 29 +++++++- .../evmUtils/src/operations/operations.ts | 3 +- .../evmUtils/src/operations/resolve/index.ts | 1 + .../resolve/resolveENSDomainOperation.test.ts | 24 +++++++ .../resolve/resolveENSDomainOperation.ts | 71 +++++++++++++++++++ .../mocks/endpoints/resolveDomain.ts | 1 - .../mocks/endpoints/resolveENSDomain.ts | 30 ++++++++ .../evmApi/integration/mocks/mockServer.ts | 2 + .../integration/test/resolveENSDomain.test.ts | 30 ++++++++ packages/evmApi/src/generated/ClientEvmApi.ts | 5 +- 11 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 .changeset/dry-zebras-ring.md create mode 100644 packages/common/evmUtils/src/operations/resolve/resolveENSDomainOperation.test.ts create mode 100644 packages/common/evmUtils/src/operations/resolve/resolveENSDomainOperation.ts create mode 100644 packages/evmApi/integration/mocks/endpoints/resolveENSDomain.ts create mode 100644 packages/evmApi/integration/test/resolveENSDomain.test.ts diff --git a/.changeset/dry-zebras-ring.md b/.changeset/dry-zebras-ring.md new file mode 100644 index 0000000000..6209f597f5 --- /dev/null +++ b/.changeset/dry-zebras-ring.md @@ -0,0 +1,6 @@ +--- +'@moralisweb3/common-evm-utils': patch +'@moralisweb3/evm-api': patch +--- + +Added `resolveENSDomain` method to the EvmApi module. diff --git a/packages/common/evmUtils/src/operations/openapi.ts b/packages/common/evmUtils/src/operations/openapi.ts index adb539178e..3bdfaa8864 100644 --- a/packages/common/evmUtils/src/operations/openapi.ts +++ b/packages/common/evmUtils/src/operations/openapi.ts @@ -213,6 +213,10 @@ export interface paths { /** Resolve a specific Unstoppable domain to its address. */ get: operations["resolveDomain"]; }; + "/resolve/ens/{domain}": { + /** Resolve a specific ENS domain to its address. */ + get: operations["resolveENSDomain"]; + }; "/{pair_address}/reserves": { /** Get the liquidity reserves for a given pair address. Only Uniswap V2 based exchanges supported at the moment. */ get: operations["getPairReserves"]; @@ -1318,7 +1322,7 @@ export interface components { }; /** * @default - * @example internal_transactions + * @example * @enum {string} */ includeList: "internal_transactions"; @@ -3834,6 +3838,29 @@ export interface operations { }; }; }; + /** Resolve a specific ENS domain to its address. */ + resolveENSDomain: { + parameters: { + path: { + /** The domain to be resolved */ + domain: string; + }; + }; + responses: { + /** Returns an address */ + 200: { + content: { + "application/json": components["schemas"]["resolve"]; + }; + }; + /** Returns an address */ + 404: { + content: { + "application/json": { [key: string]: unknown }; + }; + }; + }; + }; /** Get the liquidity reserves for a given pair address. Only Uniswap V2 based exchanges supported at the moment. */ getPairReserves: { parameters: { diff --git a/packages/common/evmUtils/src/operations/operations.ts b/packages/common/evmUtils/src/operations/operations.ts index 448ba7bdf9..462289b477 100644 --- a/packages/common/evmUtils/src/operations/operations.ts +++ b/packages/common/evmUtils/src/operations/operations.ts @@ -23,7 +23,7 @@ import { searchNFTsOperation, syncNFTContractOperation, } from './nft'; -import { resolveAddressOperation, resolveDomainOperation } from './resolve'; +import { resolveAddressOperation, resolveDomainOperation, resolveENSDomainOperation } from './resolve'; import { getTokenAllowanceOperation, getTokenMetadataBySymbolOperation, @@ -89,6 +89,7 @@ export const operations = [ getWalletTransactionsVerboseOperation, resolveAddressOperation, resolveDomainOperation, + resolveENSDomainOperation, reSyncMetadataOperation, runContractFunctionOperation, searchNFTsOperation, diff --git a/packages/common/evmUtils/src/operations/resolve/index.ts b/packages/common/evmUtils/src/operations/resolve/index.ts index 1abcda5daa..db81f370de 100644 --- a/packages/common/evmUtils/src/operations/resolve/index.ts +++ b/packages/common/evmUtils/src/operations/resolve/index.ts @@ -1,2 +1,3 @@ export * from './resolveAddressOperation'; export * from './resolveDomainOperation'; +export * from './resolveENSDomainOperation'; diff --git a/packages/common/evmUtils/src/operations/resolve/resolveENSDomainOperation.test.ts b/packages/common/evmUtils/src/operations/resolve/resolveENSDomainOperation.test.ts new file mode 100644 index 0000000000..11fb9d9291 --- /dev/null +++ b/packages/common/evmUtils/src/operations/resolve/resolveENSDomainOperation.test.ts @@ -0,0 +1,24 @@ +import MoralisCore from '@moralisweb3/common-core'; +import { resolveENSDomainOperation, ResolveENSDomainJSONRequest } from './resolveENSDomainOperation'; + +describe('resolveENSDomainOperation', () => { + let core: MoralisCore; + + beforeAll(() => { + core = MoralisCore.create(); + }); + + it('serializeRequest() serializes correctly and deserializeRequest() deserializes correctly', () => { + const request: Required = { + domain: 'nick.eth', + }; + + const serializedRequest = resolveENSDomainOperation.serializeRequest(request, core); + + expect(serializedRequest.domain).toBe(request.domain); + + const deserializedRequest = resolveENSDomainOperation.deserializeRequest(serializedRequest, core); + + expect(deserializedRequest.domain).toBe(request.domain); + }); +}); diff --git a/packages/common/evmUtils/src/operations/resolve/resolveENSDomainOperation.ts b/packages/common/evmUtils/src/operations/resolve/resolveENSDomainOperation.ts new file mode 100644 index 0000000000..b60d7389eb --- /dev/null +++ b/packages/common/evmUtils/src/operations/resolve/resolveENSDomainOperation.ts @@ -0,0 +1,71 @@ +import Core, { Camelize, Operation, ResponseAdapter } from '@moralisweb3/common-core'; +import { EvmAddress } from '../../dataTypes'; + +import { operations } from '../openapi'; + +type OperationId = 'resolveENSDomain'; + +type PathParams = operations[OperationId]['parameters']['path']; +type RequestParams = PathParams; + +type SuccessResponse = operations[OperationId]['responses']['200']['content']['application/json']; + +// Exports + +export interface ResolveENSDomainRequest extends Camelize {} + +export type ResolveENSDomainJSONRequest = ReturnType; + +export type ResolveENSDomainJSONResponse = SuccessResponse; + +export type ResolveENSDomainResponse = ReturnType; + +export interface ResolveENSDomainResponseAdapter + extends ResponseAdapter {} + +/** Resolve a specific ENS domain to its address. */ +export const resolveENSDomainOperation: Operation< + ResolveENSDomainRequest, + ResolveENSDomainJSONRequest, + ResolveENSDomainResponse, + ResolveENSDomainJSONResponse +> = { + method: 'GET', + name: 'resolveENSDomain', + id: 'resolveENSDomain', + groupName: 'resolve', + isNullable: true, + urlPathPattern: '/resolve/ens/{domain}', + urlPathParamNames: ['domain'], + + getRequestUrlParams, + serializeRequest, + deserializeRequest, + deserializeResponse, +}; + +// Methods + +function getRequestUrlParams(request: ResolveENSDomainRequest) { + return { + domain: request.domain, + }; +} + +function serializeRequest(request: ResolveENSDomainRequest) { + return { + domain: request.domain, + }; +} + +function deserializeRequest(jsonRequest: ResolveENSDomainJSONRequest): ResolveENSDomainRequest { + return { + domain: jsonRequest.domain, + }; +} + +function deserializeResponse(jsonResponse: ResolveENSDomainJSONResponse, _: ResolveENSDomainRequest, core: Core) { + return { + address: EvmAddress.create(jsonResponse.address, core), + }; +} diff --git a/packages/evmApi/integration/mocks/endpoints/resolveDomain.ts b/packages/evmApi/integration/mocks/endpoints/resolveDomain.ts index 080e0d24cd..a12217aee5 100644 --- a/packages/evmApi/integration/mocks/endpoints/resolveDomain.ts +++ b/packages/evmApi/integration/mocks/endpoints/resolveDomain.ts @@ -8,7 +8,6 @@ export const mockResolveDomain = MockScenarios.create( url: '/resolve/:domain', getParams: ({ req }) => ({ domain: req.params.domain, - currency: req.url.searchParams.get('currency'), }), }, [ diff --git a/packages/evmApi/integration/mocks/endpoints/resolveENSDomain.ts b/packages/evmApi/integration/mocks/endpoints/resolveENSDomain.ts new file mode 100644 index 0000000000..3f001e36d2 --- /dev/null +++ b/packages/evmApi/integration/mocks/endpoints/resolveENSDomain.ts @@ -0,0 +1,30 @@ +import { MockScenarios } from '@moralisweb3/test-utils'; +import { createErrorResponse } from '../response/errorResponse'; + +export const mockResolveENSDomain = MockScenarios.create( + { + name: 'mockResolveENSDomain', + method: 'get', + url: '/resolve/ens/:domain', + getParams: ({ req }) => ({ + domain: req.params.domain, + }), + }, + [ + { + condition: { + domain: 'nick.eth', + }, + response: { + address: '0xb8c2C29ee19D8307cb7255e1Cd9CbDE883A267d5', + }, + }, + { + condition: { + domain: 'unknown.eth', + }, + responseStatus: 404, + response: createErrorResponse('null'), + }, + ], +); diff --git a/packages/evmApi/integration/mocks/mockServer.ts b/packages/evmApi/integration/mocks/mockServer.ts index 05b643d1ee..82dd4418a2 100644 --- a/packages/evmApi/integration/mocks/mockServer.ts +++ b/packages/evmApi/integration/mocks/mockServer.ts @@ -48,6 +48,7 @@ import { mockGetInternalTransaction } from './endpoints/getInternalTransactions' import { mockGetTransactionVerbose } from './endpoints/getTransactionVerbose'; import { mockGetErc20Approvals } from './endpoints/getErc20Approvals'; import { mockGetErc20Burns } from './endpoints/getErc20Burns'; +import { mockResolveENSDomain } from './endpoints/resolveENSDomain'; const handler = [ mockGetDateToBlock, @@ -72,6 +73,7 @@ const handler = [ mockGetWalletTokenTransfers, mockResolveAddress, mockResolveDomain, + mockResolveENSDomain, mockGetPairAddress, mockGetPairReserves, mockRunContractFunction, diff --git a/packages/evmApi/integration/test/resolveENSDomain.test.ts b/packages/evmApi/integration/test/resolveENSDomain.test.ts new file mode 100644 index 0000000000..4d18cf88cf --- /dev/null +++ b/packages/evmApi/integration/test/resolveENSDomain.test.ts @@ -0,0 +1,30 @@ +import { EvmApi } from '../../src/EvmApi'; +import { cleanEvmApi, setupEvmApi } from '../setup'; + +describe('resolveENSDomain', () => { + let evmApi: EvmApi; + + beforeAll(() => { + evmApi = setupEvmApi(); + }); + + afterAll(() => { + cleanEvmApi(); + }); + + it('returns an address', async () => { + const result = await evmApi.resolve.resolveENSDomain({ + domain: 'nick.eth', + }); + + expect(result?.result.address.checksum).toEqual('0xb8c2C29ee19D8307cb7255e1Cd9CbDE883A267d5'); + }); + + it('returns null when API returns HTTP 404', async () => { + const result = await evmApi.resolve.resolveENSDomain({ + domain: 'unknown.eth', + }); + + expect(result).toBeNull(); + }); +}); diff --git a/packages/evmApi/src/generated/ClientEvmApi.ts b/packages/evmApi/src/generated/ClientEvmApi.ts index daf7eb44fb..8eb920c0d2 100644 --- a/packages/evmApi/src/generated/ClientEvmApi.ts +++ b/packages/evmApi/src/generated/ClientEvmApi.ts @@ -1,6 +1,6 @@ // CAUTION: This file is automatically generated. Do not edit it manually! -import { endpointWeightsOperation, EndpointWeightsResponseAdapter, runContractFunctionOperation, RunContractFunctionRequest, RunContractFunctionResponseAdapter, web3ApiVersionOperation, Web3ApiVersionResponseAdapter, getBlockOperation, GetBlockRequest, GetBlockResponseAdapter, getDateToBlockOperation, GetDateToBlockRequest, GetDateToBlockResponseAdapter, getContractEventsOperation, GetContractEventsRequest, GetContractEventsResponseAdapter, getContractLogsOperation, GetContractLogsRequest, GetContractLogsResponseAdapter, getContractNFTsOperation, GetContractNFTsRequest, GetContractNFTsResponseAdapter, getMultipleNFTsOperation, GetMultipleNFTsRequest, GetMultipleNFTsResponseAdapter, getNFTContractMetadataOperation, GetNFTContractMetadataRequest, GetNFTContractMetadataResponseAdapter, getNFTContractTransfersOperation, GetNFTContractTransfersRequest, GetNFTContractTransfersResponseAdapter, getNFTLowestPriceOperation, GetNFTLowestPriceRequest, GetNFTLowestPriceResponseAdapter, getNFTMetadataOperation, GetNFTMetadataRequest, GetNFTMetadataResponseAdapter, getNFTOwnersOperation, GetNFTOwnersRequest, GetNFTOwnersResponseAdapter, getNFTTokenIdOwnersOperation, GetNFTTokenIdOwnersRequest, GetNFTTokenIdOwnersResponseAdapter, getNFTTradesOperation, GetNFTTradesRequest, GetNFTTradesResponseAdapter, getNFTTransfersByBlockOperation, GetNFTTransfersByBlockRequest, GetNFTTransfersByBlockResponseAdapter, getNFTTransfersFromToBlockOperation, GetNFTTransfersFromToBlockRequest, GetNFTTransfersFromToBlockResponseAdapter, getNFTTransfersOperation, GetNFTTransfersRequest, GetNFTTransfersResponseAdapter, getWalletNFTCollectionsOperation, GetWalletNFTCollectionsRequest, GetWalletNFTCollectionsResponseAdapter, getWalletNFTsOperation, GetWalletNFTsRequest, GetWalletNFTsResponseAdapter, getWalletNFTTransfersOperation, GetWalletNFTTransfersRequest, GetWalletNFTTransfersResponseAdapter, reSyncMetadataOperation, ReSyncMetadataRequest, ReSyncMetadataResponseAdapter, searchNFTsOperation, SearchNFTsRequest, SearchNFTsResponseAdapter, syncNFTContractOperation, SyncNFTContractRequest, SyncNFTContractResponseAdapter, getErc20ApprovalsOperation, GetErc20ApprovalsRequest, GetErc20ApprovalsResponseAdapter, getErc20BurnsOperation, GetErc20BurnsRequest, GetErc20BurnsResponseAdapter, getErc20TransfersOperation, GetErc20TransfersRequest, GetErc20TransfersResponseAdapter, getErc20MintsOperation, GetErc20MintsRequest, GetErc20MintsResponseAdapter, getTokenAllowanceOperation, GetTokenAllowanceRequest, GetTokenAllowanceResponseAdapter, getTokenMetadataBySymbolOperation, GetTokenMetadataBySymbolRequest, GetTokenMetadataBySymbolResponseAdapter, getTokenMetadataOperation, GetTokenMetadataRequest, GetTokenMetadataResponseAdapter, getTokenPriceOperation, GetTokenPriceRequest, GetTokenPriceResponseAdapter, getTokenTransfersOperation, GetTokenTransfersRequest, GetTokenTransfersResponseAdapter, getWalletTokenBalancesOperation, GetWalletTokenBalancesRequest, GetWalletTokenBalancesResponseAdapter, getWalletTokenTransfersOperation, GetWalletTokenTransfersRequest, GetWalletTokenTransfersResponseAdapter, getInternalTransactionsOperation, GetInternalTransactionsRequest, GetInternalTransactionsResponseAdapter, getTransactionOperation, GetTransactionRequest, GetTransactionResponseAdapter, getTransactionVerboseOperation, GetTransactionVerboseRequest, GetTransactionVerboseResponseAdapter, getWalletTransactionsOperation, GetWalletTransactionsRequest, GetWalletTransactionsResponseAdapter, getWalletTransactionsVerboseOperation, GetWalletTransactionsVerboseRequest, GetWalletTransactionsVerboseResponseAdapter, getNativeBalanceOperation, GetNativeBalanceRequest, GetNativeBalanceResponseAdapter, getNativeBalancesForAddressesOperation, GetNativeBalancesForAddressesRequest, GetNativeBalancesForAddressesResponseAdapter, getPairAddressOperation, GetPairAddressRequest, GetPairAddressResponseAdapter, getPairReservesOperation, GetPairReservesRequest, GetPairReservesResponseAdapter, resolveAddressOperation, ResolveAddressRequest, ResolveAddressResponseAdapter, resolveDomainOperation, ResolveDomainRequest, ResolveDomainResponseAdapter, uploadFolderOperation, UploadFolderRequest, UploadFolderResponseAdapter } from '@moralisweb3/common-evm-utils'; +import { endpointWeightsOperation, EndpointWeightsResponseAdapter, runContractFunctionOperation, RunContractFunctionRequest, RunContractFunctionResponseAdapter, web3ApiVersionOperation, Web3ApiVersionResponseAdapter, getBlockOperation, GetBlockRequest, GetBlockResponseAdapter, getDateToBlockOperation, GetDateToBlockRequest, GetDateToBlockResponseAdapter, getContractEventsOperation, GetContractEventsRequest, GetContractEventsResponseAdapter, getContractLogsOperation, GetContractLogsRequest, GetContractLogsResponseAdapter, getContractNFTsOperation, GetContractNFTsRequest, GetContractNFTsResponseAdapter, getMultipleNFTsOperation, GetMultipleNFTsRequest, GetMultipleNFTsResponseAdapter, getNFTContractMetadataOperation, GetNFTContractMetadataRequest, GetNFTContractMetadataResponseAdapter, getNFTContractTransfersOperation, GetNFTContractTransfersRequest, GetNFTContractTransfersResponseAdapter, getNFTLowestPriceOperation, GetNFTLowestPriceRequest, GetNFTLowestPriceResponseAdapter, getNFTMetadataOperation, GetNFTMetadataRequest, GetNFTMetadataResponseAdapter, getNFTOwnersOperation, GetNFTOwnersRequest, GetNFTOwnersResponseAdapter, getNFTTokenIdOwnersOperation, GetNFTTokenIdOwnersRequest, GetNFTTokenIdOwnersResponseAdapter, getNFTTradesOperation, GetNFTTradesRequest, GetNFTTradesResponseAdapter, getNFTTransfersByBlockOperation, GetNFTTransfersByBlockRequest, GetNFTTransfersByBlockResponseAdapter, getNFTTransfersFromToBlockOperation, GetNFTTransfersFromToBlockRequest, GetNFTTransfersFromToBlockResponseAdapter, getNFTTransfersOperation, GetNFTTransfersRequest, GetNFTTransfersResponseAdapter, getWalletNFTCollectionsOperation, GetWalletNFTCollectionsRequest, GetWalletNFTCollectionsResponseAdapter, getWalletNFTsOperation, GetWalletNFTsRequest, GetWalletNFTsResponseAdapter, getWalletNFTTransfersOperation, GetWalletNFTTransfersRequest, GetWalletNFTTransfersResponseAdapter, reSyncMetadataOperation, ReSyncMetadataRequest, ReSyncMetadataResponseAdapter, searchNFTsOperation, SearchNFTsRequest, SearchNFTsResponseAdapter, syncNFTContractOperation, SyncNFTContractRequest, SyncNFTContractResponseAdapter, getErc20ApprovalsOperation, GetErc20ApprovalsRequest, GetErc20ApprovalsResponseAdapter, getErc20BurnsOperation, GetErc20BurnsRequest, GetErc20BurnsResponseAdapter, getErc20TransfersOperation, GetErc20TransfersRequest, GetErc20TransfersResponseAdapter, getErc20MintsOperation, GetErc20MintsRequest, GetErc20MintsResponseAdapter, getTokenAllowanceOperation, GetTokenAllowanceRequest, GetTokenAllowanceResponseAdapter, getTokenMetadataBySymbolOperation, GetTokenMetadataBySymbolRequest, GetTokenMetadataBySymbolResponseAdapter, getTokenMetadataOperation, GetTokenMetadataRequest, GetTokenMetadataResponseAdapter, getTokenPriceOperation, GetTokenPriceRequest, GetTokenPriceResponseAdapter, getTokenTransfersOperation, GetTokenTransfersRequest, GetTokenTransfersResponseAdapter, getWalletTokenBalancesOperation, GetWalletTokenBalancesRequest, GetWalletTokenBalancesResponseAdapter, getWalletTokenTransfersOperation, GetWalletTokenTransfersRequest, GetWalletTokenTransfersResponseAdapter, getInternalTransactionsOperation, GetInternalTransactionsRequest, GetInternalTransactionsResponseAdapter, getTransactionOperation, GetTransactionRequest, GetTransactionResponseAdapter, getTransactionVerboseOperation, GetTransactionVerboseRequest, GetTransactionVerboseResponseAdapter, getWalletTransactionsOperation, GetWalletTransactionsRequest, GetWalletTransactionsResponseAdapter, getWalletTransactionsVerboseOperation, GetWalletTransactionsVerboseRequest, GetWalletTransactionsVerboseResponseAdapter, getNativeBalanceOperation, GetNativeBalanceRequest, GetNativeBalanceResponseAdapter, getNativeBalancesForAddressesOperation, GetNativeBalancesForAddressesRequest, GetNativeBalancesForAddressesResponseAdapter, getPairAddressOperation, GetPairAddressRequest, GetPairAddressResponseAdapter, getPairReservesOperation, GetPairReservesRequest, GetPairReservesResponseAdapter, resolveAddressOperation, ResolveAddressRequest, ResolveAddressResponseAdapter, resolveDomainOperation, ResolveDomainRequest, ResolveDomainResponseAdapter, resolveENSDomainOperation, ResolveENSDomainRequest, ResolveENSDomainResponseAdapter, uploadFolderOperation, UploadFolderRequest, UploadFolderResponseAdapter } from '@moralisweb3/common-evm-utils'; import { OperationResolver, NullableOperationResolver, PaginatedOperationResolver } from '@moralisweb3/api-utils'; import { ApiModule, } from '@moralisweb3/common-core'; export abstract class ClientEvmApi extends ApiModule { @@ -179,6 +179,9 @@ export abstract class ClientEvmApi extends ApiModule { resolveDomain: (request: ResolveDomainRequest): Promise => { return new NullableOperationResolver(resolveDomainOperation, this.baseUrl, this.core).fetch(request); }, + resolveENSDomain: (request: ResolveENSDomainRequest): Promise => { + return new NullableOperationResolver(resolveENSDomainOperation, this.baseUrl, this.core).fetch(request); + }, };