Skip to content
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

feat: support Base resolution #262

Merged
merged 8 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
L1_TEST_NET_RPC_URL=https://goerli.infura.io/v3/<your_key>
L1_TEST_NET_RPC_WSS_URL=wss://goerli.infura.io/ws/v3/<your_key>
L2_TEST_NET_RPC_URL=https://polygon-mumbai.infura.io/v3/<your_key>
L2_TEST_NET_RPC_WSS_URL=wss://polygon-mumbai.g.alchemy.com/v2/<your_key>
L1_TEST_NET_RPC_URL=https://sepolia.infura.io/v3/<your_key>
L1_TEST_NET_RPC_WSS_URL=wss://sepolia.infura.io/ws/v3/<your_key>
L2_TEST_NET_RPC_URL=https://polygon-amoy.infura.io/v3/<your_key>
L2_TEST_NET_RPC_WSS_URL=wss://polygon-amoy.g.alchemy.com/v2/<your_key>
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
},
"homepage": "https://github.com/unstoppabledomains/resolution.git#readme",
"devDependencies": {
"@ethersproject/providers": "^5.4.5",
"@types/bn.js": "^4.11.6",
"@types/crypto-js": "^4.1.1",
"@types/elliptic": "^6.4.13",
Expand All @@ -76,6 +75,7 @@
"eslint": "^7.7.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-jest": "^24.1.0",
"ethers": "^6.13.4",
"husky": "^6.0.0",
"jest": "^27.0.4",
"lint-staged": "11.0.0",
Expand Down Expand Up @@ -104,7 +104,6 @@
"cross-fetch": "4.0.0",
"crypto-js": "^4.1.1",
"elliptic": "^6.5.4",
"ethereum-ens-network-map": "^1.0.2",
"js-sha256": "^0.9.0",
"js-sha3": "^0.8.0"
},
Expand Down
22 changes: 2 additions & 20 deletions src/Ens.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as contentHash from 'content-hash';
import bip44Constants from 'bip44-constants';
import {formatsByCoinType} from '@ensdomains/address-encoder';
import EnsNetworkMap from 'ethereum-ens-network-map';
import {default as ensInterface} from './contracts/ens/ens';
import {default as resolverInterface} from './contracts/ens/resolver';
import {default as nameWrapperInterface} from './contracts/ens/nameWrapper';
Expand All @@ -15,7 +14,6 @@ import {
Locations,
NamingServiceName,
Provider,
TokenUriMetadata,
BlockchainType,
DnsRecordType,
DnsRecord,
Expand Down Expand Up @@ -60,7 +58,8 @@ export default class Ens extends NamingService {
this.proxyServiceApiKey = finalSource['proxyServiceApiKey'];

const registryAddress =
finalSource['registryAddress'] || EnsNetworkMap[this.network];
finalSource['registryAddress'] ||
ensConfig.networks[this.network].contracts.ENSRegistry.address;
this.registryContract = new EthereumContract(
ensInterface,
registryAddress,
Expand Down Expand Up @@ -289,7 +288,6 @@ export default class Ens extends NamingService {
let domainName = '';
const nameWrapperMetadataResponse = await Networking.fetch(
`https://metadata.ens.domains/${this.networkName}/${this.nameWrapperContract.address}/${hash}`,
{},
);
if (nameWrapperMetadataResponse.status === 200) {
const jsonResponse = await nameWrapperMetadataResponse.json();
Expand All @@ -299,7 +297,6 @@ export default class Ens extends NamingService {

const baseRegistrarMetadataResponse = await Networking.fetch(
`https://metadata.ens.domains/${this.networkName}/${this.baseRegistrarContract.address}/${hash}`,
{},
);

if (baseRegistrarMetadataResponse.status === 200) {
Expand Down Expand Up @@ -614,19 +611,4 @@ export default class Ens extends NamingService {
this.namehash(domain),
]);
}

private async getMetadataFromTokenURI(
tokenUri: string,
): Promise<TokenUriMetadata> {
const resp = await Networking.fetch(tokenUri, {});
if (resp.ok) {
return resp.json();
}

throw new ResolutionError(ResolutionErrorCode.ServiceProviderError, {
providerMessage: await resp.text(),
method: 'UDAPI',
methodName: 'tokenURIMetadata',
});
}
}
63 changes: 52 additions & 11 deletions src/Resolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default class Resolution {

constructor(config: {sourceConfig?: SourceConfig; apiKey?: string} = {}) {
const uns = this.getUnsConfig(config);
const unsBase = this.getUnsBaseConfig(config);
const zns = this.getZnsConfig(config);
const ens = this.getEnsConfig(config);

Expand All @@ -86,6 +87,10 @@ export default class Resolution {
usedServices: [uns],
native: uns instanceof Uns ? uns : new Uns(),
},
[NamingServiceName.UNS_BASE]: {
usedServices: [unsBase],
native: unsBase instanceof Uns ? unsBase : new Uns(),
},
[NamingServiceName.ZNS]: {
usedServices: equalUdApiProviders ? [uns] : [uns, zns],
native: zns instanceof Zns ? zns : new Zns(),
Expand Down Expand Up @@ -657,7 +662,7 @@ export default class Resolution {
async email(domain: string): Promise<string> {
domain = prepareAndValidateDomain(domain);
let key = 'whois.email.value';
const serviceName = findNamingServiceName(domain);
const serviceName = await findNamingServiceName(domain);
if (serviceName === 'ENS') {
key = 'email';
}
Expand Down Expand Up @@ -1057,7 +1062,7 @@ export default class Resolution {
private async getMetadataFromTokenURI(
tokenUri: string,
): Promise<TokenUriMetadata> {
const resp = await Networking.fetch(tokenUri, {});
const resp = await Networking.fetch(tokenUri);
if (resp.ok) {
return resp.json();
}
Expand Down Expand Up @@ -1097,7 +1102,7 @@ export default class Resolution {
domain: string,
func: (service: NamingService) => T,
): Promise<UnwrapPromise<T>> {
const serviceName = findNamingServiceName(domain);
const serviceName = await findNamingServiceName(domain);
if (!serviceName) {
throw new ResolutionError(ResolutionErrorCode.UnsupportedDomain, {
domain,
Expand Down Expand Up @@ -1136,7 +1141,7 @@ export default class Resolution {
func: (service: NamingService) => Promise<boolean>,
options: {throwIfUnsupportedDomain: boolean; expectedValue: boolean},
): Promise<boolean> {
const serviceName = findNamingServiceName(domain);
const serviceName = await findNamingServiceName(domain);
if (!serviceName) {
if (!options.throwIfUnsupportedDomain) {
return !options.expectedValue;
Expand Down Expand Up @@ -1173,10 +1178,18 @@ export default class Resolution {
private async reverseGetTokenId(
address: string,
location?: UnsLocation,
): Promise<string> {
const service = this.serviceMap['UNS'].native;
const tokenId = await service.reverseOf(address, location);
return tokenId as string;
): Promise<string | null> {
let tokenId: string | null = null;

const unsService = this.serviceMap['UNS'].native;
tokenId = await unsService.reverseOf(address, location);

if (!tokenId) {
const baseUnsService = this.serviceMap['UNS_BASE'].native;
tokenId = await baseUnsService.reverseOf(address, location);
}

return tokenId;
}

private getUnsConfig(config: ResolutionConfig): Uns | UdApi {
Expand All @@ -1202,13 +1215,36 @@ export default class Resolution {
: new Uns(config.sourceConfig?.uns);
}

getZnsConfig(config: ResolutionConfig): Zns | UdApi {
private getUnsBaseConfig(config: ResolutionConfig): Uns | UdApi {
if (config.apiKey) {
return new Uns({
locations: {
Layer1: {
url: `${DEFAULT_UNS_PROXY_SERVICE_URL}/chains/eth/rpc`,
network: 'mainnet',
proxyServiceApiKey: config.apiKey,
},
Layer2: {
url: `${DEFAULT_UNS_PROXY_SERVICE_URL}/chains/base/rpc`,
network: 'base-mainnet',
proxyServiceApiKey: config.apiKey,
},
},
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can consider making one of the "layers" optional for cases similar to Base where we know that domains can exist only on one chain.

This will save us some RPC calls on querying L1 when we don't need to.


return isApi(config.sourceConfig?.uns)
? new UdApi(config.sourceConfig?.uns)
: new Uns(config.sourceConfig?.uns);
}

private getZnsConfig(config: ResolutionConfig): Zns | UdApi {
return isApi(config.sourceConfig?.zns)
? new UdApi(config.sourceConfig?.zns)
: new Zns(config.sourceConfig?.zns);
}

getEnsConfig(config: ResolutionConfig): Ens | UdApi {
private getEnsConfig(config: ResolutionConfig): Ens | UdApi {
if (config.apiKey) {
return new Ens({
url: `${DEFAULT_UNS_PROXY_SERVICE_URL}/chains/eth/rpc`,
Expand All @@ -1231,5 +1267,10 @@ type ServicesEntry = {
};

function isApi(obj: any): obj is Api {
return obj && obj.api;
return (
typeof obj === 'object' &&
obj !== null &&
'api' in obj &&
typeof obj.api === 'boolean'
);
}
8 changes: 4 additions & 4 deletions src/UdApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export default class UdApi extends NamingService {

constructor(api?: Api) {
super();
this.url = api?.url || 'https://unstoppabledomains.com/api/v1';
this.url = api?.url || 'https://unstoppabledomains.com/api/v1'; // TODO: this is about to be deprecated
const DefaultUserAgent =
'cross-fetch/3.1.4 (+https://github.com/lquixada/cross-fetch)';
'cross-fetch/4.0.0 (+https://github.com/lquixada/cross-fetch)';
const CustomUserAgent = `${DefaultUserAgent} Resolution`;
this.headers = {'X-user-agent': CustomUserAgent};
}
Expand Down Expand Up @@ -77,7 +77,7 @@ export default class UdApi extends NamingService {
}

async twitter(domain: string): Promise<string> {
const serviceName = findNamingServiceName(domain);
const serviceName = await findNamingServiceName(domain);
if (serviceName !== NamingServiceName.UNS) {
throw new ResolutionError(ResolutionErrorCode.UnsupportedMethod, {
domain,
Expand Down Expand Up @@ -150,7 +150,7 @@ export default class UdApi extends NamingService {

private async getMetadata(tokenId: string): Promise<ResolutionResponse> {
const tokenUri = `${this.url}/${tokenId}`;
const resp = await Networking.fetch(tokenUri, {}).catch((err) => {
const resp = await Networking.fetch(tokenUri).catch((err) => {
throw new ResolutionError(ResolutionErrorCode.MetadataEndpointError, {
tokenUri: tokenUri || 'undefined',
errorMessage: err.message,
Expand Down
4 changes: 2 additions & 2 deletions src/Uns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export default class Uns extends NamingService {
this.unsl2 = new UnsInternal(
UnsLocation.Layer2,
source.locations.Layer2,
BlockchainType.MATIC,
BlockchainType.POL,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is going to be POL for both Polygon and Base configs. It's probably fine as is, but might be worth passing the blockchain type into constructor args.

}

Expand Down Expand Up @@ -447,7 +447,7 @@ export default class Uns extends NamingService {

private async getMetadata(tokenId: string): Promise<DomainMetadata> {
const tokenUri = await this.getTokenUri(tokenId);
const resp = await Networking.fetch(tokenUri, {}).catch((err) => {
const resp = await Networking.fetch(tokenUri).catch((err) => {
throw new ResolutionError(ResolutionErrorCode.MetadataEndpointError, {
tokenUri: tokenUri || 'undefined',
errorMessage: err.message,
Expand Down
Loading
Loading