diff --git a/src.ts/providers/abstract-provider.ts b/src.ts/providers/abstract-provider.ts index 0a7448e249..468ce46f9c 100644 --- a/src.ts/providers/abstract-provider.ts +++ b/src.ts/providers/abstract-provider.ts @@ -57,6 +57,7 @@ import type { PreparedTransactionRequest, Provider, ProviderEvent, TransactionRequest } from "./provider.js"; +import { RnsResolver } from "./rns-resolver.js"; type Timer = ReturnType; @@ -1189,6 +1190,8 @@ export class AbstractProvider implements Provider { } async resolveName(name: string): Promise{ + if (name.endsWith('.rsk')) { return (await new RnsResolver(this)).getAddress(name); } + const resolver = await this.getResolver(name); if (resolver) { return await resolver.getAddress(); } return null; @@ -1199,7 +1202,12 @@ export class AbstractProvider implements Provider { const node = namehash(address.substring(2).toLowerCase() + ".addr.reverse"); try { - + const chainId = (await this.getNetwork()).chainId; + + if (chainId === 30n) { + return await new RnsResolver(this).getName(address); + } + const ensAddr = await EnsResolver.getEnsAddress(this); const ensContract = new Contract(ensAddr, [ "function resolver(bytes32) view returns (address)" diff --git a/src.ts/providers/rns-resolver.ts b/src.ts/providers/rns-resolver.ts new file mode 100644 index 0000000000..96419cd09a --- /dev/null +++ b/src.ts/providers/rns-resolver.ts @@ -0,0 +1,114 @@ +/** + * RNS is a service which allows easy-to-remember names to map to + * network addresses on Rootstock. + * + * @_section: api/providers/rns-resolver:RNS Resolver [about-rns-rsolver] + */ + +import { ZeroAddress } from "../constants/index.js"; +import { Contract } from "../contract/index.js"; +import { namehash } from "../hash/index.js"; + +import type { AbstractProvider } from "./abstract-provider.js"; + +// REF: https://developers.rsk.co/rif/rns/architecture/registry/ +const RNS_REGISTRY_ADDRESS = "0xcb868aeabd31e2b66f74e9a55cf064abb31a4ad5"; + +const stripHexPrefix = (hex: string): string => hex.slice(2); + +const RNS_REGISTRY_ABI = [ + "function resolver(bytes32 node) public view returns (address)", +]; + +const RNS_ADDR_RESOLVER_ABI = [ + "function addr(bytes32 node) public view returns (address)", +]; + +const RNS_NAME_RESOLVER_ABI = [ + "function name(bytes32 node) external view returns (string)", +]; + +/** + * A connected object to a resolved RNS name resolver, which can be + * used to query additional details. + */ +export class RnsResolver { + /** + * The connected provider. + */ + provider!: AbstractProvider; + + /** + * RNS registry contract + */ + #rnsRegistryContract: Contract; + + + constructor(provider: AbstractProvider) { + this.provider = provider; + this.#rnsRegistryContract = new Contract( + RNS_REGISTRY_ADDRESS, + RNS_REGISTRY_ABI, + this.provider + ); + } + + /** + * Resolves to the address for %%name%% or null if the + * provided %%name%% has not been configured. + */ + async getAddress(name: string): Promise { + const nameHash = namehash(name) + const resolverAddress = await this.#rnsRegistryContract.resolver(nameHash) + + if (resolverAddress === ZeroAddress) { + return null + } + + const addrResolverContract = new Contract( + resolverAddress, + RNS_ADDR_RESOLVER_ABI, + this.provider + ) + + const address = await addrResolverContract.addr(nameHash) + + if (address === undefined || address === null) { + return null + } + + return address; + } + + /** + * Resolves to the name for %%address%% or null if the + * provided %%address%% has not been configured. + */ + async getName(address: string): Promise { + const reverseRecordHash = namehash( + `${stripHexPrefix(address)}.addr.reverse` + ); + + const resolverAddress = await this.#rnsRegistryContract.resolver( + reverseRecordHash + ); + + if (resolverAddress === ZeroAddress) { + return null; + } + + const nameResolverContract = new Contract( + resolverAddress, + RNS_NAME_RESOLVER_ABI, + this.provider + ); + + const name = await nameResolverContract.name(reverseRecordHash); + + if (name === undefined) { + return null; + } + + return name; + } +}