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

Add Rootstock Name service RNS #4786

Open
wants to merge 1 commit 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
10 changes: 9 additions & 1 deletion src.ts/providers/abstract-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import type {
PreparedTransactionRequest, Provider, ProviderEvent,
TransactionRequest
} from "./provider.js";
import { RnsResolver } from "./rns-resolver.js";

type Timer = ReturnType<typeof setTimeout>;

Expand Down Expand Up @@ -1189,6 +1190,8 @@ export class AbstractProvider implements Provider {
}

async resolveName(name: string): Promise<null | string>{
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;
Expand All @@ -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)"
Expand Down
114 changes: 114 additions & 0 deletions src.ts/providers/rns-resolver.ts
Original file line number Diff line number Diff line change
@@ -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<null | string> {
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<null | string> {
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;
}
}