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

ENSIP-10 Reverse Resolution #4632

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
12 changes: 12 additions & 0 deletions src.ts/_tests/test-providers-ccip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,16 @@ describe("Test CCIP execution", function() {
const result = await provider.call(tx);
verify(address, calldata, result);
});

// it("query a ensip-10 reverse registrar that's offchain", async function() {
// this.timeout(60000);

// const provider = connect("goerli");

// // this accounts primary has an offchain reverse resolver
// const address = '0xEB4200f750335eFb67E726485445d302D64B1c8A';
// const name = await provider.lookupAddress(address);
// console.log(name);
// });

})
48 changes: 11 additions & 37 deletions src.ts/providers/abstract-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@
// of Signer/ENS name to address so we can sync respond to listenerCount.

import { getAddress, resolveAddress } from "../address/index.js";
import { ZeroAddress } from "../constants/index.js";
import { Contract } from "../contract/index.js";
import { namehash } from "../hash/index.js";
import { Transaction } from "../transaction/index.js";
import {
concat, dataLength, dataSlice, hexlify, isHexString,
getBigInt, getBytes, getNumber,
isCallException, isError, makeError, assert, assertArgument,
isCallException, makeError, assert, assertArgument,
FetchRequest,
toBeArray, toQuantity,
defineProperties, EventPayload, resolveProperties,
Expand Down Expand Up @@ -1196,41 +1193,18 @@ export class AbstractProvider implements Provider {

async lookupAddress(address: string): Promise<null | string> {
address = getAddress(address);
const node = namehash(address.substring(2).toLowerCase() + ".addr.reverse");

try {

const ensAddr = await EnsResolver.getEnsAddress(this);
const ensContract = new Contract(ensAddr, [
"function resolver(bytes32) view returns (address)"
], this);

const resolver = await ensContract.resolver(node);
if (resolver == null || resolver === ZeroAddress) { return null; }

const resolverContract = new Contract(resolver, [
"function name(bytes32) view returns (string)"
], this);
const name = await resolverContract.name(node);

// Failed forward resolution
const check = await this.resolveName(name);
if (check !== address) { return null; }

return name;

} catch (error) {
// No data was returned from the resolver
if (isError(error, "BAD_DATA") && error.value === "0x") {
return null;
const resolver = await this.getResolver(address.substring(2).toLowerCase() + ".addr.reverse");
if (resolver) {
const name = await resolver.getName();
if (name) { // possible optimization: name.includes('.')
const expect = await this.resolveName(name);
// check roundtrip
assert(address === expect, "address->name->address mismatch", "VALUE_MISMATCH", {lhs: address, rhs: expect});
return name;
}

// Something reerted
if (isError(error, "CALL_EXCEPTION")) { return null; }

throw error;
}

// i think ALL errors should propagate out as reverse names are a critical piece
// of ENS infrastructure and saying a primary is null should be a true-positive
return null;
}

Expand Down
9 changes: 9 additions & 0 deletions src.ts/providers/ens-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export class EnsResolver {
"function addr(bytes32, uint) view returns (bytes)",
"function text(bytes32, string) view returns (string)",
"function contenthash(bytes32) view returns (bytes)",
"function name(bytes32) view returns (string)",
], provider);

}
Expand Down Expand Up @@ -313,6 +314,14 @@ export class EnsResolver {
});
}

/**
* Resolves to the ENSIP-3 name record for %%key%%, or ``null``
* if unconfigured.
*/
async getName(): Promise<null | string> {
return this.#fetch("name(bytes32)");
}

/**
* Resolves to the EIP-634 text record for %%key%%, or ``null``
* if unconfigured.
Expand Down
15 changes: 15 additions & 0 deletions src.ts/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,20 @@ export interface ActionRejectedError extends EthersError<"ACTION_REJECTED"> {
reason: "expired" | "rejected" | "pending"
}

/**
* This Error indicates `lhs` != `rhs`.
*/
export interface ValueMismatchError extends EthersError<"VALUE_MISMATCH"> {
/**
* The left-hand side.
*/
lhs: any,
/**
* The right-hand side.
*/
rhs: any
}

// Coding; converts an ErrorCode its Typed Error

/**
Expand Down Expand Up @@ -608,6 +622,7 @@ export type CodedEthersError<T> =
T extends "UNCONFIGURED_NAME" ? UnconfiguredNameError:

T extends "ACTION_REJECTED" ? ActionRejectedError:
T extends "VALUE_MISMATCH" ? ValueMismatchError:

never;

Expand Down