From a5a986932cae7703a7e4e4ce6be25707554b079c Mon Sep 17 00:00:00 2001 From: Adil Iqbal Date: Sat, 10 Dec 2022 16:14:06 +0100 Subject: [PATCH] Added support for RNS domain resolution to address --- src/components/modals/AddressModal.tsx | 88 ++++++++++++++++++++- src/constants/WalletAndCurrencyConstants.ts | 1 + src/locales/en_US.ts | 2 +- src/locales/strings/enUS.json | 2 +- 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/components/modals/AddressModal.tsx b/src/components/modals/AddressModal.tsx index e72745073da..955de3eeead 100644 --- a/src/components/modals/AddressModal.tsx +++ b/src/components/modals/AddressModal.tsx @@ -9,7 +9,7 @@ import { sprintf } from 'sprintf-js' import { refreshAllFioAddresses } from '../../actions/FioAddressActions' import ENS_LOGO from '../../assets/images/ens_logo.png' import FIO_LOGO from '../../assets/images/fio/fio_logo.png' -import { ENS_DOMAINS, UNSTOPPABLE_DOMAINS } from '../../constants/WalletAndCurrencyConstants' +import { ENS_DOMAINS, RNS_DOMAINS, UNSTOPPABLE_DOMAINS } from '../../constants/WalletAndCurrencyConstants' import { lstrings } from '../../locales/strings' import { checkPubAddress, FioAddresses, getFioAddressCache } from '../../modules/FioAddress/util' import { connect } from '../../types/reactRedux' @@ -58,6 +58,8 @@ type Props = StateProps & OwnProps & DispatchProps & ThemeProps export class AddressModalComponent extends React.Component { fioCheckQueue: number = 0 + rskProvider?: ethers.providers.JsonRpcProvider + rnsRegistryContract?: ethers.Contract constructor(props: Props) { super(props) @@ -139,13 +141,15 @@ export class AddressModalComponent extends React.Component { } checkIfDomain = (domain: string): boolean => { - return this.checkIfUnstoppableDomain(domain) || this.checkIfEnsDomain(domain) + return this.checkIfUnstoppableDomain(domain) || this.checkIfEnsDomain(domain) || this.checkIfRnsDomain(domain) } checkIfUnstoppableDomain = (name: string): boolean => UNSTOPPABLE_DOMAINS.some(domain => name.endsWith(domain)) checkIfEnsDomain = (name: string): boolean => ENS_DOMAINS.some(domain => name.endsWith(domain)) + checkIfRnsDomain = (name: string): boolean => RNS_DOMAINS.some(domain => name.endsWith(domain)) + fetchUnstoppableDomainAddress = async (domain: string, currencyTicker: string): Promise => { domain = domain.trim().toLowerCase() if (!this.checkIfUnstoppableDomain(domain)) { @@ -177,6 +181,85 @@ export class AddressModalComponent extends React.Component { return address } + // This approach considers resolution for tokens + getRnsChainIdFromPluginId = (pluginId: string): number => { + switch (pluginId) { + case 'rsk': + return 137 + case 'ethereum': + return 60 + case 'ethereumclassic': + return 61 + case 'bitcoin': + return 0 + case 'litecoin': + return 2 + case 'dogecoin': + return 3 + case 'dash': + return 5 + case 'ripple': + return 144 + case 'bitcoincash': + return 145 + case 'binance': + return 714 + case 'stellar': + return 148 + case 'eos': + return 194 + default: + return -1 + } + } + + fetchRnsAddress = async (domain: string): Promise => { + try { + const chainId = this.getRnsChainIdFromPluginId(this.props.coreWallet.currencyInfo.pluginId) + if (chainId === -1) { + throw new ResolutionError('UnspecifiedCurrency', { domain }) + } + if (this.rskProvider == null) { + const rskCurrencyInfo: EdgeCurrencyConfig = this.props.account.currencyConfig.rsk + const rskServerInfo = rskCurrencyInfo.currencyInfo.defaultSettings.otherSettings.rpcServers[0] + this.rskProvider = new ethers.providers.JsonRpcProvider(rskServerInfo) + } + if (!this.rnsRegistryContract) { + // REF: https://developers.rsk.co/rif/rns/architecture/registry/ + const RNS_REGISTRY_ADDRESS = '0xcb868aeabd31e2b66f74e9a55cf064abb31a4ad5' // hardcoded RNS registry address + this.rnsRegistryContract = new ethers.Contract( + RNS_REGISTRY_ADDRESS, + ['function resolver(bytes32 node) public view returns (address)'], + this.rskProvider + ) + } + const nameHash = ethers.utils.namehash(domain) + const resolverAddress = await this.rnsRegistryContract.resolver(nameHash) + if (resolverAddress === ethers.constants.AddressZero) { + throw new ResolutionError('UnregisteredDomain', { domain }) + } + // Check if current selected currency is on RSK chain 137 if not check for multichain address + let address = '' + if (chainId === 137) { + const addrResolverContract = new ethers.Contract(resolverAddress, ['function addr(bytes32 node) public view returns (address)'], this.rskProvider) + address = await addrResolverContract.addr(nameHash) + } else { + const multichainAddrResolverContract = new ethers.Contract( + resolverAddress, + ['function addr(bytes32 node, uint coinType) external view returns(bytes memory)'], + this.rskProvider + ) + address = await multichainAddrResolverContract.addr(nameHash, chainId) + } + if (address === undefined || address === null) { + throw new ResolutionError('UnregisteredDomain', { domain }) + } + return address.toLowerCase() + } catch (e) { + throw new ResolutionError('UnregisteredDomain', { domain }) + } + } + resolveAddress = async (domain: string, currencyTicker: string) => { if (!domain) return try { @@ -184,6 +267,7 @@ export class AddressModalComponent extends React.Component { let addr: string if (this.checkIfUnstoppableDomain(domain)) addr = await this.fetchUnstoppableDomainAddress(domain, currencyTicker) else if (this.checkIfEnsDomain(domain)) addr = await this.fetchEnsAddress(domain) + else if (this.checkIfRnsDomain(domain)) addr = await this.fetchRnsAddress(domain) else { throw new ResolutionError('UnsupportedDomain', { domain }) } diff --git a/src/constants/WalletAndCurrencyConstants.ts b/src/constants/WalletAndCurrencyConstants.ts index 0ad5b9f8588..2cad8494997 100644 --- a/src/constants/WalletAndCurrencyConstants.ts +++ b/src/constants/WalletAndCurrencyConstants.ts @@ -961,3 +961,4 @@ export const FIO_ADDRESS_DELIMITER = '@' export const UNSTOPPABLE_DOMAINS = ['.coin', '.wallet', '.bitcoin', '.x', '.888', '.nft', '.dao', '.blockchain', '.zil', '.crypto'] export const ENS_DOMAINS = ['.eth', '.luxe', '.kred', '.xyz', '.art'] +export const RNS_DOMAINS = ['.rsk'] diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 53e7377bd64..cb111bd8ea2 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -926,7 +926,7 @@ const strings = { personalize_wallet_title: 'Personalize Your Wallet', get_started_button: 'Get Started', not_now_button: 'Not Now', - scan_address_modal_title: 'Enter Recipient FIO, ENS, or Public Address', + scan_address_modal_title: 'Enter Recipient FIO, ENS, RNS, or Public Address', enter_any_title: 'Enter any of the following:', enter_any_body: '1. Public address to send money to\n2. Private key to sweep\n3. Wallet Connect URI to connect to a dApp\n4. Edge Login URI to login to another device\n\nEdge will auto-detect the URI format and allow you to select an appropriate wallet', diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index 9dee7c9bf14..dc6b130ae3c 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -829,7 +829,7 @@ "personalize_wallet_title": "Personalize Your Wallet", "get_started_button": "Get Started", "not_now_button": "Not Now", - "scan_address_modal_title": "Enter Recipient FIO, ENS, or Public Address", + "scan_address_modal_title": "Enter Recipient FIO, ENS, RNS, or Public Address", "enter_any_title": "Enter any of the following:", "enter_any_body": "1. Public address to send money to\n2. Private key to sweep\n3. Wallet Connect URI to connect to a dApp\n4. Edge Login URI to login to another device\n\nEdge will auto-detect the URI format and allow you to select an appropriate wallet", "enter_any_input_hint": "Enter any of the above",