From 2d37f8eec55430eb4b5f54d3997e89091d561f1e Mon Sep 17 00:00:00 2001 From: Ilan <36084092+ilanolkies@users.noreply.github.com> Date: Tue, 2 Jun 2020 11:56:42 -0300 Subject: [PATCH 1/3] I18n (#97) --- src/composer.ts | 15 +- src/errors/ErrorWrapper.ts | 14 ++ src/errors/RNSError.ts | 16 +- src/errors/errors.json | 314 +++++++++++++++++++++++++++++++--- src/errors/index.ts | 1 + src/index.ts | 5 +- src/registrations.ts | 12 +- src/resolutions.ts | 36 ++-- src/subdomains.ts | 32 ++-- src/types/enums.ts | 13 ++ src/types/error-dictionary.ts | 10 +- src/types/options.ts | 5 +- src/utils.ts | 13 +- test/local/rns.i18n.test.ts | 66 +++++++ test/utils.ts | 9 +- 15 files changed, 476 insertions(+), 85 deletions(-) create mode 100644 src/errors/ErrorWrapper.ts create mode 100644 test/local/rns.i18n.test.ts diff --git a/src/composer.ts b/src/composer.ts index bd8c080..81160c6 100644 --- a/src/composer.ts +++ b/src/composer.ts @@ -4,11 +4,12 @@ import { Composable, Options, ContractAddresses, Contracts, } from './types'; import { createRegistry, createContractAddresses } from './factories'; -import RNSError, { LIBRARY_NOT_COMPOSED } from './errors'; +import RNSError, { LIBRARY_NOT_COMPOSED, NO_ACCOUNTS_TO_SIGN } from './errors'; import { getCurrentAddress } from './utils'; import { TransactionOptions } from './types/options'; +import ErrorWrapper from './errors/ErrorWrapper'; -export default abstract class implements Composable { +export default abstract class extends ErrorWrapper implements Composable { private _contractAddresses!: ContractAddresses; private _composed!: boolean; @@ -29,6 +30,8 @@ export default abstract class implements Composable { * @param options - Overrides network defaults. Optional on RSK Mainnet and RSK Testnet, required for other networks. */ constructor(blockchainApi: Web3 | any, options?: Options) { + super(options && options.lang); + this.blockchainApi = blockchainApi as Web3; // rsk3 eth namespace are exposed in the top level namespace @@ -77,7 +80,13 @@ export default abstract class implements Composable { from: customOptions.from, }; } else { - const sender = await getCurrentAddress(this.blockchainApi); + let sender; + + try { + sender = await getCurrentAddress(this.blockchainApi); + } catch { + this._throw(NO_ACCOUNTS_TO_SIGN); + } options = { from: sender, diff --git a/src/errors/ErrorWrapper.ts b/src/errors/ErrorWrapper.ts new file mode 100644 index 0000000..3bbcd83 --- /dev/null +++ b/src/errors/ErrorWrapper.ts @@ -0,0 +1,14 @@ +import RNSError from './RNSError'; +import { Lang } from '../types/enums'; + +export default class { + private lang: Lang; + + constructor(lang = Lang.en) { + this.lang = lang; + } + + protected _throw(errorId: string) { + throw new RNSError(errorId, this.lang); + } +} diff --git a/src/errors/RNSError.ts b/src/errors/RNSError.ts index 5b6e710..3e723ea 100644 --- a/src/errors/RNSError.ts +++ b/src/errors/RNSError.ts @@ -1,21 +1,31 @@ import { DEVPORTAL_ERRORS_URL } from '../constants'; import errors from './errors.json'; import { ErrorDictionary } from '../types'; +import { Lang } from '../types/enums'; export default class extends Error { ref: string; id: string; - constructor(errorId: string) { + constructor(errorId: string, lang = Lang.en) { let error = (errors as ErrorDictionary)[errorId]; if (!error) { error = { - id: 'KB000', message: 'Unknown error', + id: 'KB000', + message: { + en: 'Unknown error', + es: 'Error desconocido', + ja: '不明なエラー', + ko: '알수없는 오류', + pt: 'Erro desconhecido', + ru: 'Неизвестная ошибка', + zh: '未知错误', + }, }; } - super(error.message); + super(error.message[lang]); this.id = error.id; this.ref = `${DEVPORTAL_ERRORS_URL}#${error.id.toLowerCase()}`; } diff --git a/src/errors/errors.json b/src/errors/errors.json index 2fcd34a..4902643 100644 --- a/src/errors/errors.json +++ b/src/errors/errors.json @@ -1,26 +1,290 @@ { - "NO_ADDR_RESOLUTION_SET": { "id": "KB001", "message": "No addr resolution set" }, - "NO_ADDR_RESOLUTION": { "id": "KB002", "message": "No addr resolution" }, - "NO_RESOLVER": { "id": "KB003", "message": "No resolver" }, - "LIBRARY_NOT_COMPOSED": { "id": "KB004", "message": "Library not composed" }, - "NO_ADDRESSES_PROVIDED": { "id": "KB005", "message": "No contract addresses provided" }, - "NO_CHAIN_ADDR_RESOLUTION": { "id": "KB006", "message": "No chain address resolution" }, - "NO_CHAIN_ADDR_RESOLUTION_SET": { "id": "KB007", "message": "No chain address resolution set" }, - "SEARCH_ONLY_SIMPLE_DOMAINS": { "id": "KB008", "message": "Search only domains" }, - "SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS": { "id": "KB009", "message": "Search only .rsk domains" }, - "INVALID_DOMAIN": { "id": "KB010", "message": "Invalid domain, must be alphanumeric and lower case" }, - "INVALID_LABEL": { "id": "KB011", "message": "Invalid label, must be alphanumeric and lower case" }, - "DOMAIN_NOT_EXISTS": { "id": "KB012", "message": "The given domain does not exist" }, - "NO_NAME_RESOLUTION": { "id": "KB013", "message": "No name resolution" }, - "NO_REVERSE_RESOLUTION_SET": { "id": "KB014", "message": "No reverse resolution set" }, - "NO_ACCOUNTS_TO_SIGN": { "id": "KB015", "message": "There are no accounts to sign the transaction" }, - "SUBDOMAIN_NOT_AVAILABLE": { "id": "KB016", "message": "The subdomain is not available" }, - "INVALID_ADDRESS": { "id": "KB017", "message": "The given address is invalid" }, - "NO_SET_ADDR": { "id": "KB018", "message": "The resolver does not implements setAddr method" }, - "INVALID_CHECKSUM_ADDRESS": { "id": "KB019", "message": "The address provided is not valid for the given blockchain" }, - "NO_TLD_OWNER": { "id": "KB020", "message": "The given TLD does not exists" }, - "NO_AVAILABLE_METHOD": { "id": "KB021", "message": "The owner of the TLD does not implement the available method" }, - "NO_REVERSE_REGISTRAR": { "id": "KB022", "message": "No reverse registrar" }, - "NO_SET_NAME_METHOD": { "id": "KB023", "message": "The reverse registrar does not implement setName method" }, - "NO_SET_CHAIN_ADDR": { "id": "KB024", "message": "The resolver does not implement setChainAddr method" } -} + "NO_ADDR_RESOLUTION_SET": { + "id": "KB001", + "message": { + "en": "No addr resolution set", + "es": "Sin resolución de addr (dirección) establecida", + "ja": "アドレスの解決が設定されていません", + "ko": "주소 결정 미설정", + "pt": "Nenhuma resolução de endereço definida", + "ru": "Разрешение для адреса не установлено", + "zh": "无地址解析集" + } + }, + "NO_ADDR_RESOLUTION": { + "id": "KB002", + "message": { + "en": "No addr resolution", + "es": "Sin resolución de addr", + "ja": "アドレスの解決が存在しません", + "ko": "주소 결정 없음", + "pt": "Sem resolução de endereço", + "ru": "Разрешение для адреса отсутствует", + "zh": "无地址解析" + } + }, + "NO_RESOLVER": { + "id": "KB003", + "message": { + "en": "No resolver", + "es": "Sin resolver", + "ja": "Resolverが存在しません", + "ko": "Resolver 없음", + "pt": "Sem resolver", + "ru": "Resolver отсутствует", + "zh": "无解析器" + } + }, + "LIBRARY_NOT_COMPOSED": { + "id": "KB004", + "message": { + "en": "Library not composed", + "es": "Biblioteca no compuesta", + "ja": "ライブラリが構成されていません", + "ko": "라이브러리 미구성", + "pt": "Biblioteca não composta", + "ru": "Библиотека не сформирована", + "zh": "库未组成" + } + }, + "NO_ADDRESSES_PROVIDED": { + "id": "KB005", + "message": { + "en": "No contract addresses provided", + "es": "No se proporcionan direcciones de contrato", + "ja": "コントラクトアドレスが提供されていません", + "ko": "컨트랙트 주소 미제공", + "pt": "Nenhum endereço de contrato fornecido", + "ru": "Адреса контактов не предоставлены", + "zh": "未提供合约地址" + } + }, + "NO_CHAIN_ADDR_RESOLUTION": { + "id": "KB006", + "message": { + "en": "No chain address resolution", + "es": "Sin resolución de dirección de cadena", + "ja": "チェーンアドレスの解決が存在しません", + "ko": "체인 주소 결정 없음", + "pt": "Nenhuma resolução de endereço da cadeia", + "ru": "Разрешение для адреса цепочки отсутствует", + "zh": "无链地址解析" + } + }, + "NO_CHAIN_ADDR_RESOLUTION_SET": { + "id": "KB007", + "message": { + "en": "No chain address resolution set", + "es": "Sin resolución de dirección de cadena establecida", + "ja": "チェーンアドレスの解決が設定されていません", + "ko": "체인 주소 결정 미설정", + "pt": "Sem resolução de endereço da cadeia", + "ru": "Разрешение для адреса цепочки не установлено", + "zh": "无链地址解析集" + } + }, + "SEARCH_ONLY_SIMPLE_DOMAINS": { + "id": "KB008", + "message": { + "en": "Search only domains", + "es": "Buscar solo dominios", + "ja": "ドメインのみ検索", + "ko": "도메인만 검색", + "pt": "Pesquisar apenas domínios", + "ru": "Искать только домены", + "zh": "仅搜索域" + } + }, + "SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS": { + "id": "KB009", + "message": { + "en": "Search only .rsk domains", + "es": "Buscar solo dominios .rsk", + "ja": ".rskドメインのみ検索", + "ko": ".rsk 도메인만 검색", + "pt": "Pesquisar apenas domínios .rsk", + "ru": "Искать только домены .rsk", + "zh": "仅搜索 .rsk 域" + } + }, + "INVALID_DOMAIN": { + "id": "KB010", + "message": { + "en": "Invalid domain, must be alphanumeric and lower case", + "es": "Dominio no válido; debe ser alfanumérico y en minúsculas", + "ja": "ドメインが無効です。小文字の英数字で入力してください", + "ko": "유효하지 않은 도메인. 글자, 숫자 및 소문자만 사용 가능", + "pt": "Domínio inválido, deve ser alfanumérico e minúsculo", + "ru": "Недействительный домен, домен должен быть буквенно-цифровым и строчным", + "zh": "无效的域,必须是字母数字和小写字母" + } + }, + "INVALID_LABEL": { + "id": "KB011", + "message": { + "en": "Invalid label, must be alphanumeric and lower case", + "es": "Etiqueta no válida; debe ser alfanumérica y en minúsculas", + "ja": "ラベルが無効です。小文字の英数字で入力してください", + "ko": "유효하지 않은 라벨. 글자, 숫자 및 소문자만 사용 가능", + "pt": "Etiqueta inválida, deve ser alfanumérica e minúscula", + "ru": "Недействительная метка, метка должна быть буквенно-цифровой и строчной", + "zh": "无效标签,必须是字母数字和小写字母" + } + }, + "DOMAIN_NOT_EXISTS": { + "id": "KB012", + "message": { + "en": "The given domain does not exist", + "es": "El dominio proporcionado no existe", + "ja": "与えられたドメインが存在しません", + "ko": "해당 도메인이 존재하지 않습니다", + "pt": "O domínio fornecido não existe", + "ru": "Данный домен не существует", + "zh": "指定的域不存在" + } + }, + "NO_NAME_RESOLUTION": { + "id": "KB013", + "message": { + "en": "No name resolution", + "es": "Sin resolución de nombre", + "ja": "名前の解決が存在しません", + "ko": "이름 결정 없음", + "pt": "Sem resolução de nomes", + "ru": "Разрешение для имени отсутствует", + "zh": "无名字解析" + } + }, + "NO_REVERSE_RESOLUTION_SET": { + "id": "KB014", + "message": { + "en": "No reverse resolution set", + "es": "Sin resolución inversa establecida", + "ja": "リバース解決が設定されていません", + "ko": "리버스 결정 미설정", + "pt": "Nenhuma resolução reversa definida", + "ru": "Обратное разрешение не установлено", + "zh": "无反向解析集" + } + }, + "NO_ACCOUNTS_TO_SIGN": { + "id": "KB015", + "message": { + "en": "There are no accounts to sign the transaction", + "es": "No hay cuentas para firmar la transacción", + "ja": "トランザクションをサインするアカウントが存在しません", + "ko": "거래에 서명할 계정이 없습니다", + "pt": "Não há contas para assinar a transação", + "ru": "Учетные записи для подписи транзакции отсутствуют", + "zh": "没有用于签署交易的帐户" + } + }, + "SUBDOMAIN_NOT_AVAILABLE": { + "id": "KB016", + "message": { + "en": "The subdomain is not available", + "es": "El subdominio no está disponible", + "ja": "サブドメインは利用できません", + "ko": "서브도메인을 사용할 수 없습니다", + "pt": "O subdomínio não está disponível", + "ru": "Поддомен недоступен", + "zh": "子域不可用" + } + }, + "INVALID_ADDRESS": { + "id": "KB017", + "message": { + "en": "The given address is invalid", + "es": "La dirección proporcionada no es válida", + "ja": "与えられたアドレスは無効です", + "ko": "해당 주소가 유효하지 않습니다", + "pt": "O endereço fornecido é inválido", + "ru": "Данный адрес недействителен", + "zh": "指定的地址无效" + } + }, + "NO_SET_ADDR": { + "id": "KB018", + "message": { + "en": "The resolver does not implements setAddr method", + "es": "El resolver no implementa el método setAddr", + "ja": "ResolverはsetAddr手法を実装していません", + "ko": "Resolver가 setAddr 방식을 구현하지 않습니다", + "pt": "O resolver não implementa o método setAddr", + "ru": "Resolver не реализует setAddr метод", + "zh": "解析器未实施setAddr方法" + } + }, + "INVALID_CHECKSUM_ADDRESS": { + "id": "KB019", + "message": { + "en": "The address provided is not valid for the given blockchain", + "es": "La dirección proporcionada no es válida para la blockchain suministrada", + "ja": "与えられたアドレスはこのブロックチェーンでは無効です", + "ko": "제공된 주소가 해당 블록체인에서 유효하지 않습니다", + "pt": "O endereço fornecido não é válido para o blockchain especificado", + "ru": "Указанный адрес недействителен для данного блокчейна", + "zh": "提供的地址对于指定的区块链无效" + } + }, + "NO_TLD_OWNER": { + "id": "KB020", + "message": { + "en": "The given TLD does not exists", + "es": "El TLD proporcionado no existe", + "ja": "与えられたTLDは存在しません", + "ko": "해당 TLD가 존재하지 않습니다", + "pt": "O TLD fornecido não existe", + "ru": "Данный TLD не существует", + "zh": "指定的TLD不存在" + } + }, + "NO_AVAILABLE_METHOD": { + "id": "KB021", + "message": { + "en": "The owner of the TLD does not implement the available method", + "es": "El propietario del TLD no implementa el método disponible", + "ja": "TLDの所有者は利用可能な手法を実装していません", + "ko": "TLD의 주인이 제공 방식을 구현하지 않습니다", + "pt": "O proprietário do TLD não implementa o método disponível", + "ru": "Владелец TLD не реализует доступный метод", + "zh": "TLD的所有者未实施可用方法" + } + }, + "NO_REVERSE_REGISTRAR": { + "id": "KB022", + "message": { + "en": "No reverse registrar", + "es": "Sin registrar inverso", + "ja": "リバースRegistrarが存在しません", + "ko": "리버스 registrar 없음", + "pt": "Nenhum registrar reverso", + "ru": "Обратный Registrar отсутствует", + "zh": "无反向注册商" + } + }, + "NO_SET_NAME_METHOD": { + "id": "KB023", + "message": { + "en": "The reverse registrar does not implement setName method", + "es": "El registrar inverso no implementa el método setName", + "ja": "リバースRegistrarはsetName手法を実装していません", + "ko": "리버스 registrar가 setName 방식을 구현하지 않습니다", + "pt": "O registrar reverso não implementa o método setName", + "ru": "Обратный Registrar не реализует setName метод", + "zh": "反向注册商未实施setName方法" + } + }, + "NO_SET_CHAIN_ADDR": { + "id": "KB024", + "message": { + "en": "The resolver does not implement setChainAddr method", + "es": "El resolver no implementa el método setChainAddr", + "ja": "ResolverはsetChainAddr手法を実装していません", + "ko": "Resolver가 setChainAddr 방식을 구현하지 않습니다", + "pt": "O resolver não implementa o método setChainAddr", + "ru": "Resolver не реализует setChainAddr метод", + "zh": "解析器未实施setChainAddr方法" + } + } +} \ No newline at end of file diff --git a/src/errors/index.ts b/src/errors/index.ts index 70ba00f..693fdeb 100644 --- a/src/errors/index.ts +++ b/src/errors/index.ts @@ -1,6 +1,7 @@ import RNSError from './RNSError'; export default RNSError; +export { default as ErrorWrapper } from './ErrorWrapper'; export const NO_ADDR_RESOLUTION_SET = 'NO_ADDR_RESOLUTION_SET'; export const NO_ADDR_RESOLUTION = 'NO_ADDR_RESOLUTION'; diff --git a/src/index.ts b/src/index.ts index fc7e257..d90e6d0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ import { Subdomains as ISubdomains, Registrations as IRegistrations, } from './types'; -import RNSError, { LIBRARY_NOT_COMPOSED } from './errors'; +import { LIBRARY_NOT_COMPOSED } from './errors'; import Resolutions from './resolutions'; import Registrations from './registrations'; import Subdomains from './subdomains'; @@ -14,7 +14,6 @@ import Composer from './composer'; import * as utils from './utils'; import { TransactionOptions } from './types/options'; - /** * RNS JavaScript library. */ @@ -50,7 +49,7 @@ export default class extends Composer implements RNS { */ get contracts(): Contracts { if (!this._contracts) { - throw new RNSError(LIBRARY_NOT_COMPOSED); + this._throw(LIBRARY_NOT_COMPOSED); } return this._contracts; } diff --git a/src/registrations.ts b/src/registrations.ts index de2b26f..fb068a6 100644 --- a/src/registrations.ts +++ b/src/registrations.ts @@ -5,7 +5,7 @@ import { Registrations, Options } from './types'; import { isValidDomain, isValidTld, isValidLabel, labelhash, namehash, hasMethod, } from './utils'; -import RNSError, { +import { INVALID_DOMAIN, SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS, INVALID_LABEL, NO_TLD_OWNER, NO_AVAILABLE_METHOD, } from './errors'; @@ -32,7 +32,7 @@ export default class extends Composer implements Registrations { ).call(); if (nodeOwnerAddress === ZERO_ADDRESS) { - throw new RNSError(NO_TLD_OWNER); + this._throw(NO_TLD_OWNER); } const hasAvailableMethod = await hasMethod( @@ -41,7 +41,7 @@ export default class extends Composer implements Registrations { AVAILABLE_INTERFACE, ); if (!hasAvailableMethod) { - throw new RNSError(errorMessage); + this._throw(errorMessage); } const nodeOwner: Contract = contractFactory(this.blockchainApi, nodeOwnerAddress); @@ -51,7 +51,7 @@ export default class extends Composer implements Registrations { private async _searchAvailabilityByLabel(label: string): Promise { if (!isValidLabel(label)) { - throw new RNSError(INVALID_LABEL); + this._throw(INVALID_LABEL); } let availables = []; @@ -72,10 +72,10 @@ export default class extends Composer implements Registrations { private async _searchAvailabilityByDomain(domain: string): Promise { if (!isValidDomain(domain)) { - throw new RNSError(INVALID_DOMAIN); + this._throw(INVALID_DOMAIN); } if (!isValidTld(domain)) { - throw new RNSError(SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS); + this._throw(SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS); } const [label, tld] = domain.split('.'); diff --git a/src/resolutions.ts b/src/resolutions.ts index d39548a..b6c17f0 100644 --- a/src/resolutions.ts +++ b/src/resolutions.ts @@ -17,7 +17,7 @@ import { hasMethod, namehash, hasAccounts, isValidAddress, isValidChecksumAddress, isValidDomain, toChecksumAddress, } from './utils'; -import RNSError, { +import { NO_RESOLVER, NO_ADDR_RESOLUTION, NO_ADDR_RESOLUTION_SET, NO_CHAIN_ADDR_RESOLUTION, NO_CHAIN_ADDR_RESOLUTION_SET, NO_NAME_RESOLUTION, NO_REVERSE_RESOLUTION_SET, NO_ACCOUNTS_TO_SIGN, NO_SET_ADDR, INVALID_ADDRESS, INVALID_CHECKSUM_ADDRESS, @@ -60,7 +60,7 @@ export default class extends Composer implements Resolutions { const resolverAddress: string = await this._contracts.registry.methods.resolver(node).call(); if (resolverAddress === ZERO_ADDRESS) { - throw new RNSError(noResolverError || NO_RESOLVER); + this._throw(noResolverError || NO_RESOLVER); } const resolver: Contract = contractFactory(this.blockchainApi, resolverAddress); @@ -70,7 +70,7 @@ export default class extends Composer implements Resolutions { ); if (!supportsInterface) { - throw new RNSError(errorMessage); + this._throw(errorMessage); } return resolver; @@ -79,20 +79,20 @@ export default class extends Composer implements Resolutions { private _validateAddress(addr: string, chainId?: ChainId) { if (!chainId || chainId === ChainId.RSK || chainId === ChainId.ETHEREUM) { if (!isValidAddress(addr)) { - throw new RNSError(INVALID_ADDRESS); + this._throw(INVALID_ADDRESS); } if (!chainId) { if (!isValidChecksumAddress(addr, this.currentNetworkId)) { - throw new RNSError(INVALID_CHECKSUM_ADDRESS); + this._throw(INVALID_CHECKSUM_ADDRESS); } } else if (chainId === ChainId.RSK) { if (!isValidChecksumAddress(addr, NetworkId.RSK_MAINNET)) { - throw new RNSError(INVALID_CHECKSUM_ADDRESS); + this._throw(INVALID_CHECKSUM_ADDRESS); } } else if (chainId === ChainId.ETHEREUM) { if (!isValidChecksumAddress(addr)) { - throw new RNSError(INVALID_CHECKSUM_ADDRESS); + this._throw(INVALID_CHECKSUM_ADDRESS); } } } @@ -124,7 +124,7 @@ export default class extends Composer implements Resolutions { const addr: string = await resolver.methods.addr(node).call(); if (addr === ZERO_ADDRESS) { - throw new RNSError(NO_ADDR_RESOLUTION_SET); + this._throw(NO_ADDR_RESOLUTION_SET); } return toChecksumAddress(addr, this.currentNetworkId); @@ -156,7 +156,7 @@ export default class extends Composer implements Resolutions { const addr: string = await resolver.methods.chainAddr(node, chainId).call(); if (!addr || addr === ZERO_ADDRESS) { - throw new RNSError(NO_CHAIN_ADDR_RESOLUTION_SET); + this._throw(NO_CHAIN_ADDR_RESOLUTION_SET); } // return checksum address just if it is a EVM blockchain address @@ -191,7 +191,7 @@ export default class extends Composer implements Resolutions { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { - throw new RNSError(NO_ACCOUNTS_TO_SIGN); + this._throw(NO_ACCOUNTS_TO_SIGN); } this._validateAddress(addr); @@ -232,7 +232,7 @@ export default class extends Composer implements Resolutions { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { - throw new RNSError(NO_ACCOUNTS_TO_SIGN); + this._throw(NO_ACCOUNTS_TO_SIGN); } this._validateAddress(addr, chainId); @@ -276,14 +276,14 @@ export default class extends Composer implements Resolutions { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { - throw new RNSError(NO_ACCOUNTS_TO_SIGN); + this._throw(NO_ACCOUNTS_TO_SIGN); } this._validateAddress(resolver); const domainOwner = await this._contracts.registry.methods.owner(namehash(domain)).call(); if (domainOwner === ZERO_ADDRESS) { - throw new RNSError(DOMAIN_NOT_EXISTS); + this._throw(DOMAIN_NOT_EXISTS); } const node: string = namehash(domain); @@ -311,18 +311,18 @@ export default class extends Composer implements Resolutions { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { - throw new RNSError(NO_ACCOUNTS_TO_SIGN); + this._throw(NO_ACCOUNTS_TO_SIGN); } if (!isValidDomain(name)) { - throw new RNSError(INVALID_DOMAIN); + this._throw(INVALID_DOMAIN); } const reverseRegistrarOwner = await this._contracts.registry.methods.owner( ADDR_REVERSE_NAMEHASH, ).call(); if (reverseRegistrarOwner === ZERO_ADDRESS) { - throw new RNSError(NO_REVERSE_REGISTRAR); + this._throw(NO_REVERSE_REGISTRAR); } const hasSetNameMethod = await hasMethod( @@ -331,7 +331,7 @@ export default class extends Composer implements Resolutions { SET_NAME_INTERFACE, ); if (!hasSetNameMethod) { - throw new RNSError(NO_SET_NAME_METHOD); + this._throw(NO_SET_NAME_METHOD); } const reverseRegistrar = createReverseRegistrar(this.blockchainApi, reverseRegistrarOwner); @@ -368,7 +368,7 @@ export default class extends Composer implements Resolutions { const name: string = await resolver.methods.name(node).call(); if (!name) { - throw new RNSError(NO_REVERSE_RESOLUTION_SET); + this._throw(NO_REVERSE_RESOLUTION_SET); } return name; diff --git a/src/subdomains.ts b/src/subdomains.ts index eff50dc..86af55d 100644 --- a/src/subdomains.ts +++ b/src/subdomains.ts @@ -1,7 +1,7 @@ import Web3 from 'web3'; import { TransactionReceipt } from 'web3-eth'; import { Subdomains, Options, Resolutions } from './types'; -import RNSError, { +import { SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS, INVALID_DOMAIN, INVALID_LABEL, DOMAIN_NOT_EXISTS, NO_ACCOUNTS_TO_SIGN, SUBDOMAIN_NOT_AVAILABLE, @@ -48,23 +48,23 @@ export default class extends Composer implements Subdomains { private _validateDomainAndLabel(domain: string, label: string): void { if (!isValidDomain(domain)) { - throw new RNSError(INVALID_DOMAIN); + this._throw(INVALID_DOMAIN); } if (!isValidTld(domain)) { - throw new RNSError(SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS); + this._throw(SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS); } if (!isValidLabel(label)) { - throw new RNSError(INVALID_LABEL); + this._throw(INVALID_LABEL); } } private _validateAddress(addr: string) { if (!isValidAddress(addr)) { - throw new RNSError(INVALID_ADDRESS); + this._throw(INVALID_ADDRESS); } if (!isValidChecksumAddress(addr, this.currentNetworkId)) { - throw new RNSError(INVALID_CHECKSUM_ADDRESS); + this._throw(INVALID_CHECKSUM_ADDRESS); } } @@ -89,7 +89,7 @@ export default class extends Composer implements Subdomains { const domainOwner = await this._contracts.registry.methods.owner(namehash(domain)).call(); if (domainOwner === ZERO_ADDRESS) { - throw new RNSError(DOMAIN_NOT_EXISTS); + this._throw(DOMAIN_NOT_EXISTS); } const node: string = namehash(`${label}.${domain}`); @@ -122,7 +122,7 @@ export default class extends Composer implements Subdomains { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { - throw new RNSError(NO_ACCOUNTS_TO_SIGN); + this._throw(NO_ACCOUNTS_TO_SIGN); } this._validateDomainAndLabel(domain, label); @@ -131,7 +131,7 @@ export default class extends Composer implements Subdomains { const domainOwner = await this._contracts.registry.methods.owner(namehash(domain)).call(); if (domainOwner === ZERO_ADDRESS) { - throw new RNSError(DOMAIN_NOT_EXISTS); + this._throw(DOMAIN_NOT_EXISTS); } const node: string = namehash(`${domain}`); @@ -170,7 +170,7 @@ export default class extends Composer implements Subdomains { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { - throw new RNSError(NO_ACCOUNTS_TO_SIGN); + this._throw(NO_ACCOUNTS_TO_SIGN); } this._validateDomainAndLabel(domain, label); @@ -185,11 +185,11 @@ export default class extends Composer implements Subdomains { const domainOwner = await this._contracts.registry.methods.owner(namehash(domain)).call(); if (domainOwner === ZERO_ADDRESS) { - throw new RNSError(DOMAIN_NOT_EXISTS); + this._throw(DOMAIN_NOT_EXISTS); } if (!await this.available(domain, label)) { - throw new RNSError(SUBDOMAIN_NOT_AVAILABLE); + this._throw(SUBDOMAIN_NOT_AVAILABLE); } const node: string = namehash(`${domain}`); @@ -198,9 +198,15 @@ export default class extends Composer implements Subdomains { if (options && options.from) { sender = options.from; } else { - sender = await getCurrentAddress(this.blockchainApi); + try { + sender = await getCurrentAddress(this.blockchainApi); + } catch { + this._throw(NO_ACCOUNTS_TO_SIGN); + } } + sender = sender as string; + if (!addr) { return this._setSubnodeOwner(node, label, owner || sender, options); } if (!owner || owner === sender) { diff --git a/src/types/enums.ts b/src/types/enums.ts index 119478d..4b5b086 100644 --- a/src/types/enums.ts +++ b/src/types/enums.ts @@ -15,3 +15,16 @@ export enum ChainId { ETHEREUM = '0x8000003c', LITECOIN = '0x80000002' } + +/** + * Supported feedback languages + */ +export enum Lang { + en = 'en', + es = 'es', + ja = 'ja', + ko = 'ko', + pt = 'pt', + ru = 'ru', + zh = 'zh' +} diff --git a/src/types/error-dictionary.ts b/src/types/error-dictionary.ts index c4f174f..eb2e86d 100644 --- a/src/types/error-dictionary.ts +++ b/src/types/error-dictionary.ts @@ -1,6 +1,14 @@ export interface ErrorDictionary { [id: string]: { id: string; - message: string; + message: { + en: string; + es: string; + ja: string; + ko: string; + pt: string; + ru: string; + zh: string; + }; }; } diff --git a/src/types/options.ts b/src/types/options.ts index 95927f8..b891e83 100644 --- a/src/types/options.ts +++ b/src/types/options.ts @@ -1,3 +1,5 @@ +import { Lang } from './enums'; + /** * Contains the necessary contract addresses to run the current lib. */ @@ -13,7 +15,8 @@ export interface ContractAddresses { */ export interface Options { contractAddresses?: ContractAddresses, - networkId?: number + networkId?: number, + lang?: Lang, } /** diff --git a/src/utils.ts b/src/utils.ts index de923e6..7628ef7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,7 +4,6 @@ import { keccak256 } from 'js-sha3'; import * as rskjutils from 'rskjs-util'; import { AVAILABLE_TLDS } from './constants'; import { NetworkId } from './types'; -import RNSError, { NO_ACCOUNTS_TO_SIGN } from './errors'; /** * Checks if the contract in the given address has the given method @@ -46,15 +45,9 @@ export const hasAccounts = async (web3: Web3) => { * * @returns Current address */ -export const getCurrentAddress = async (web3: Web3): Promise => { - let accounts = []; - try { - accounts = await web3.eth.getAccounts(); - } catch { - throw new RNSError(NO_ACCOUNTS_TO_SIGN); - } - return accounts[0]; -}; +export const getCurrentAddress = async (web3: Web3): Promise => ( + web3.eth.getAccounts().then((a) => a[0]) +); /** * Validates the given address diff --git a/test/local/rns.i18n.test.ts b/test/local/rns.i18n.test.ts new file mode 100644 index 0000000..bc24ee5 --- /dev/null +++ b/test/local/rns.i18n.test.ts @@ -0,0 +1,66 @@ +import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; +import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; +import { + contract, web3, defaultSender, +} from '@openzeppelin/test-environment'; +import { hash as namehash } from 'eth-ens-namehash'; +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import { NO_RESOLVER } from '../../src/errors'; +import { ZERO_ADDRESS } from '../../src/constants'; +import { asyncExpectThrowRNSError } from '../utils'; +import RNS from '../../src/index'; +import { labelhash } from '../../src/utils'; +import { Lang } from '../../src/types/enums'; +import { Options } from '../../src/types'; + +const web3Instance = web3 as unknown as Web3; +const rsk3Instance = new Rsk3(web3.currentProvider); + +describe.each([ + [web3Instance], + [rsk3Instance], +])('addr resolution', (blockchainApiInstance) => { + describe.each([ + [Lang.en], + [Lang.es], + [Lang.ja], + [Lang.ko], + [Lang.pt], + [Lang.ru], + [Lang.zh], + ])('- lang %s', (lang) => { + const TLD = 'rsk'; + + let registry: any; + let publicResolver: any; + let options: Options; + + beforeEach(async () => { + const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); + const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); + registry = await Registry.new(); + publicResolver = await PublicResolver.new(registry.address); + + await registry.setDefaultResolver(publicResolver.address); + + await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); + + options = { + contractAddresses: { + registry: registry.address, + }, + lang, + }; + + await registry.setSubnodeOwner(namehash(TLD), labelhash('noresolver'), defaultSender); + await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); + }); + + it('should throw an error in the current language', async () => { + const rns = new RNS(blockchainApiInstance, options); + + await asyncExpectThrowRNSError(() => rns.addr('noresolver.rsk'), NO_RESOLVER, lang); + }); + }); +}); diff --git a/test/utils.ts b/test/utils.ts index 0515b3c..9a2dd25 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,4 +1,5 @@ import RNSError from '../src/errors'; +import { Lang } from '../src/types/enums'; export const PUBLIC_NODE_MAINNET = 'https://public-node.rsk.co'; export const PUBLIC_NODE_TESTNET = 'https://public-node.testnet.rsk.co'; @@ -14,10 +15,14 @@ const asyncTryCatchAssert = async (prom: any, assertion: (error: any) => void) = } }; -export const asyncExpectThrowRNSError = async (prom: any, expectedError: string) => { +export const asyncExpectThrowRNSError = async ( + prom: any, + expectedError: string, + expectedLang = Lang.en, +) => { await asyncTryCatchAssert( prom, - (error) => expect(error).toEqual(new RNSError(expectedError)), + (error) => expect(error).toEqual(new RNSError(expectedError, expectedLang)), ); }; From 083e2364652e3f22ba82c09053ed48919bd928e1 Mon Sep 17 00:00:00 2001 From: Javier Esses Date: Wed, 10 Jun 2020 20:38:44 -0300 Subject: [PATCH 2/3] New resolver integration (#99) --- .eslintrc.js | 2 +- package-lock.json | 1191 ++++++++++++++++- package.json | 6 +- src/@types/content-hash/index.d.ts | 1 + src/constants.ts | 2 + src/contenthash-helper.ts | 74 + src/errors/errors.json | 38 +- src/errors/index.ts | 3 + src/factories/index.ts | 25 +- src/index.ts | 25 + src/resolutions.ts | 212 ++- src/resolvers/ProxyAdminData.json | 1 + src/resolvers/ProxyFactoryData.json | 2 + src/resolvers/ResolverV1Data.json | 1 + src/types/enums.ts | 12 +- src/types/resolutions.ts | 23 +- src/types/rns.ts | 17 + test/local/addr.test.ts | 113 ++ ...ns.available.test.ts => available.test.ts} | 35 +- test/local/chainAddr.test.ts | 120 ++ test/local/contenthash.test.ts | 95 ++ .../{rns.error.test.ts => error.test.ts} | 0 test/local/helpers.ts | 97 ++ test/local/{rns.i18n.test.ts => i18n.test.ts} | 22 +- ...esolve.reverse.test.ts => reverse.test.ts} | 45 +- test/local/rns.resolve.addr.test.ts | 95 -- test/local/rns.resolve.chainAddr.test.ts | 112 -- test/local/rns.resolve.setAddr.test.ts | 197 --- test/local/rns.resolve.setChainAddr.test.ts | 190 --- test/local/setAddr.test.ts | 197 +++ test/local/setChainAddr.test.ts | 250 ++++ test/local/setContenthash.test.ts | 99 ++ ...etResolver.test.ts => setResolver.test.ts} | 34 +- ....setReverse.test.ts => setReverse.test.ts} | 32 +- .../{rns.setup.test.ts => setup.test.ts} | 18 +- ...e.test.ts => subdomains.available.test.ts} | 30 +- ...eate.test.ts => subdomains.create.test.ts} | 29 +- ...er.test.ts => subdomains.setOwner.test.ts} | 25 +- .../{rns.utils.test.ts => utils.test.ts} | 6 +- test/public-nodes/addr.test.ts | 69 + ...ns.available.test.ts => available.test.ts} | 0 test/public-nodes/chainAddr.test.ts | 71 + test/public-nodes/contenthash.test.ts | 42 + ...s.resolve.name.test.ts => reverse.test.ts} | 16 +- test/public-nodes/rns.resolve.addr.test.ts | 46 - .../rns.resolve.chainAddr.test.ts | 52 - ...esolve.setAddr.test.ts => setAddr.test.ts} | 2 +- ...etResolver.test.ts => setResolver.test.ts} | 2 +- .../{rns.setup.test.ts => setup.test.ts} | 18 +- ...e.test.ts => subdomains.available.test.ts} | 26 +- ...s => subdomains.setOwnerAndCreate.test.ts} | 4 +- test/utils.ts | 32 +- 52 files changed, 2817 insertions(+), 1039 deletions(-) create mode 100644 src/@types/content-hash/index.d.ts create mode 100644 src/contenthash-helper.ts create mode 100644 src/resolvers/ProxyAdminData.json create mode 100644 src/resolvers/ProxyFactoryData.json create mode 100644 src/resolvers/ResolverV1Data.json create mode 100644 test/local/addr.test.ts rename test/local/{rns.available.test.ts => available.test.ts} (89%) create mode 100644 test/local/chainAddr.test.ts create mode 100644 test/local/contenthash.test.ts rename test/local/{rns.error.test.ts => error.test.ts} (100%) create mode 100644 test/local/helpers.ts rename test/local/{rns.i18n.test.ts => i18n.test.ts} (60%) rename test/local/{rns.resolve.reverse.test.ts => reverse.test.ts} (56%) delete mode 100644 test/local/rns.resolve.addr.test.ts delete mode 100644 test/local/rns.resolve.chainAddr.test.ts delete mode 100644 test/local/rns.resolve.setAddr.test.ts delete mode 100644 test/local/rns.resolve.setChainAddr.test.ts create mode 100644 test/local/setAddr.test.ts create mode 100644 test/local/setChainAddr.test.ts create mode 100644 test/local/setContenthash.test.ts rename test/local/{rns.resolve.setResolver.test.ts => setResolver.test.ts} (79%) rename test/local/{rns.resolve.setReverse.test.ts => setReverse.test.ts} (79%) rename test/local/{rns.setup.test.ts => setup.test.ts} (84%) rename test/local/{rns.subdomains.available.test.ts => subdomains.available.test.ts} (80%) rename test/local/{rns.subdomains.create.test.ts => subdomains.create.test.ts} (90%) rename test/local/{rns.subdomains.setOwner.test.ts => subdomains.setOwner.test.ts} (91%) rename test/local/{rns.utils.test.ts => utils.test.ts} (98%) create mode 100644 test/public-nodes/addr.test.ts rename test/public-nodes/{rns.available.test.ts => available.test.ts} (100%) create mode 100644 test/public-nodes/chainAddr.test.ts create mode 100644 test/public-nodes/contenthash.test.ts rename test/public-nodes/{rns.resolve.name.test.ts => reverse.test.ts} (72%) delete mode 100644 test/public-nodes/rns.resolve.addr.test.ts delete mode 100644 test/public-nodes/rns.resolve.chainAddr.test.ts rename test/public-nodes/{rns.resolve.setAddr.test.ts => setAddr.test.ts} (87%) rename test/public-nodes/{rns.resolve.setResolver.test.ts => setResolver.test.ts} (87%) rename test/public-nodes/{rns.setup.test.ts => setup.test.ts} (88%) rename test/public-nodes/{rns.subdomains.available.test.ts => subdomains.available.test.ts} (71%) rename test/public-nodes/{rns.subdomains.setOwnerAndCreate.test.ts => subdomains.setOwnerAndCreate.test.ts} (83%) diff --git a/.eslintrc.js b/.eslintrc.js index 6898510..44bed85 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,6 +32,6 @@ module.exports = { 'eol-last': 'error', 'no-underscore-dangle': ['error', { 'allowAfterThis': true }], 'max-len': ['error', { 'code': 100, 'ignoreStrings': true, 'ignoreComments': true }], - 'class-methods-use-this': ['error', { 'exceptMethods': ['_validateDomainAndLabel'] }] + 'class-methods-use-this': ['error', { 'exceptMethods': ['_validateDomainAndLabel', '_createResolver', '_getCoinTypeFromChainId'] }] } } diff --git a/package-lock.json b/package-lock.json index a5d278e..105a758 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@rsksmart/rns", - "version": "1.7.1", + "version": "1.7.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -751,6 +751,23 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-class-properties": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.1.tgz", + "integrity": "sha512-Gf2Yx/iRs1JREDtVZ56OrjjgFHCaldpTnuy9BHla10qyVT3YkIIGEtoDWhyop0ksu1GvNjHIoYRBqm3zoR1jyQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz", + "integrity": "sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA==", + "dev": true + } + } + }, "@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", @@ -769,6 +786,23 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.1.tgz", + "integrity": "sha512-XyHIFa9kdrgJS91CUH+ccPVTnJShr8nLGc5bG2IhGXv5p1Rd+8BleGE5yzIg2Nc1QZAdHDa0Qp4m6066OL96Iw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz", + "integrity": "sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA==", + "dev": true + } + } + }, "@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", @@ -778,6 +812,23 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.1.tgz", + "integrity": "sha512-uTd0OsHrpe3tH5gRPTxG8Voh99/WCU78vIm5NMRYPAqC8lR4vajt6KkCAknCHrx24vkPdd/05yfdGSB4EIY2mg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz", + "integrity": "sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA==", + "dev": true + } + } + }, "@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", @@ -1330,6 +1381,15 @@ } } }, + "@ensdomains/address-encoder": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.7.tgz", + "integrity": "sha512-p43NCgeyF3Q5ZEhEa24SN/UYUTKZIvFHwQ3xT8xqv4/iBbf7+efOP8Pl6kHbu6HI6pdWhTMvHOUR4UEDu4MN1g==", + "requires": { + "bech32": "^1.1.3", + "crypto-addr-codec": "^0.1.7" + } + }, "@ensdomains/ens": { "version": "0.3.11", "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.3.11.tgz", @@ -2593,6 +2653,555 @@ } } }, + "@openzeppelin/upgrades": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades/-/upgrades-2.8.0.tgz", + "integrity": "sha512-LzjTQPeljPsgHDPdZyH9cMCbIHZILgd2cpNcYEkdsC2IylBYRHShlbEDXJV9snnqg9JWfzPiKIqyj3XVliwtqQ==", + "dev": true, + "requires": { + "@types/cbor": "^2.0.0", + "axios": "^0.18.0", + "bignumber.js": "^7.2.0", + "cbor": "^4.1.5", + "chalk": "^2.4.1", + "ethers": "^4.0.20", + "glob": "^7.1.3", + "lodash": "^4.17.15", + "semver": "^5.5.1", + "spinnies": "^0.4.2", + "truffle-flattener": "^1.4.0", + "web3": "1.2.2", + "web3-eth": "1.2.2", + "web3-eth-contract": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ethers": { + "version": "4.0.47", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.47.tgz", + "integrity": "sha512-hssRYhngV4hiDNeZmVU/k5/E8xmLG8UpcNUzg6mb7lqhgpFPH/t7nuv20RjRrEf0gblzvi2XwR5Te+V3ZFc9pQ==", + "dev": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.5.2", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", + "dev": true + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=", + "dev": true + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", + "dev": true + }, + "web3": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.2.tgz", + "integrity": "sha512-/ChbmB6qZpfGx6eNpczt5YSUBHEA5V2+iUCbn85EVb3Zv6FVxrOo5Tv7Lw0gE2tW7EEjASbCyp3mZeiZaCCngg==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-bzz": "1.2.2", + "web3-core": "1.2.2", + "web3-eth": "1.2.2", + "web3-eth-personal": "1.2.2", + "web3-net": "1.2.2", + "web3-shh": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-bzz": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.2.tgz", + "integrity": "sha512-b1O2ObsqUN1lJxmFSjvnEC4TsaCbmh7Owj3IAIWTKqL9qhVgx7Qsu5O9cD13pBiSPNZJ68uJPaKq380QB4NWeA==", + "dev": true, + "requires": { + "@types/node": "^10.12.18", + "got": "9.6.0", + "swarm-js": "0.1.39", + "underscore": "1.9.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.24.tgz", + "integrity": "sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA==", + "dev": true + } + } + }, + "web3-core": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.2.tgz", + "integrity": "sha512-miHAX3qUgxV+KYfaOY93Hlc3kLW2j5fH8FJy6kSxAv+d4d5aH0wwrU2IIoJylQdT+FeenQ38sgsCnFu9iZ1hCQ==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "@types/node": "^12.6.1", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-requestmanager": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-core-method": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.2.tgz", + "integrity": "sha512-szR4fDSBxNHaF1DFqE+j6sFR/afv9Aa36OW93saHZnrh+iXSrYeUUDfugeNcRlugEKeUCkd4CZylfgbK2SKYJA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-core-promievent": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.2.tgz", + "integrity": "sha512-tKvYeT8bkUfKABcQswK6/X79blKTKYGk949urZKcLvLDEaWrM3uuzDwdQT3BNKzQ3vIvTggFPX9BwYh0F1WwqQ==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.2.tgz", + "integrity": "sha512-a+gSbiBRHtHvkp78U2bsntMGYGF2eCb6219aMufuZWeAZGXJ63Wc2321PCbA8hF9cQrZI4EoZ4kVLRI4OF15Hw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "web3-providers-http": "1.2.2", + "web3-providers-ipc": "1.2.2", + "web3-providers-ws": "1.2.2" + } + }, + "web3-core-subscriptions": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.2.tgz", + "integrity": "sha512-QbTgigNuT4eicAWWr7ahVpJyM8GbICsR1Ys9mJqzBEwpqS+RXTRVSkwZ2IsxO+iqv6liMNwGregbJLq4urMFcQ==", + "dev": true, + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2" + } + }, + "web3-eth": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.2.tgz", + "integrity": "sha512-UXpC74mBQvZzd4b+baD4Ocp7g+BlwxhBHumy9seyE/LMIcMlePXwCKzxve9yReNpjaU16Mmyya6ZYlyiKKV8UA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-eth-accounts": "1.2.2", + "web3-eth-contract": "1.2.2", + "web3-eth-ens": "1.2.2", + "web3-eth-iban": "1.2.2", + "web3-eth-personal": "1.2.2", + "web3-net": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-eth-abi": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.2.tgz", + "integrity": "sha512-Yn/ZMgoOLxhTVxIYtPJ0eS6pnAnkTAaJgUJh1JhZS4ekzgswMfEYXOwpMaD5eiqPJLpuxmZFnXnBZlnQ1JMXsw==", + "dev": true, + "requires": { + "ethers": "4.0.0-beta.3", + "underscore": "1.9.1", + "web3-utils": "1.2.2" + }, + "dependencies": { + "@types/node": { + "version": "10.17.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.24.tgz", + "integrity": "sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA==", + "dev": true + }, + "elliptic": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", + "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "inherits": "^2.0.1" + } + }, + "ethers": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", + "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", + "dev": true, + "requires": { + "@types/node": "^10.3.2", + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.3.3", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.3", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", + "dev": true + } + } + }, + "web3-eth-accounts": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.2.tgz", + "integrity": "sha512-KzHOEyXOEZ13ZOkWN3skZKqSo5f4Z1ogPFNn9uZbKCz+kSp+gCAEKxyfbOsB/JMAp5h7o7pb6eYsPCUBJmFFiA==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "crypto-browserify": "3.12.0", + "eth-lib": "0.2.7", + "ethereumjs-common": "^1.3.2", + "ethereumjs-tx": "^2.1.1", + "scrypt-shim": "github:web3-js/scrypt-shim", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "web3-eth-contract": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz", + "integrity": "sha512-EKT2yVFws3FEdotDQoNsXTYL798+ogJqR2//CaGwx3p0/RvQIgfzEwp8nbgA6dMxCsn9KOQi7OtklzpnJMkjtA==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-eth-ens": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.2.tgz", + "integrity": "sha512-CFjkr2HnuyMoMFBoNUWojyguD4Ef+NkyovcnUc/iAb9GP4LHohKrODG4pl76R5u61TkJGobC2ij6TyibtsyVYg==", + "dev": true, + "requires": { + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-eth-contract": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-eth-iban": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.2.tgz", + "integrity": "sha512-gxKXBoUhaTFHr0vJB/5sd4i8ejF/7gIsbM/VvemHT3tF5smnmY6hcwSMmn7sl5Gs+83XVb/BngnnGkf+I/rsrQ==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.2" + } + }, + "web3-eth-personal": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.2.tgz", + "integrity": "sha512-4w+GLvTlFqW3+q4xDUXvCEMU7kRZ+xm/iJC8gm1Li1nXxwwFbs+Y+KBK6ZYtoN1qqAnHR+plYpIoVo27ixI5Rg==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-net": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-net": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.2.tgz", + "integrity": "sha512-K07j2DXq0x4UOJgae65rWZKraOznhk8v5EGSTdFqASTx7vWE/m+NqBijBYGEsQY1lSMlVaAY9UEQlcXK5HzXTw==", + "dev": true, + "requires": { + "web3-core": "1.2.2", + "web3-core-method": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-providers-http": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.2.tgz", + "integrity": "sha512-BNZ7Hguy3eBszsarH5gqr9SIZNvqk9eKwqwmGH1LQS1FL3NdoOn7tgPPdddrXec4fL94CwgNk4rCU+OjjZRNDg==", + "dev": true, + "requires": { + "web3-core-helpers": "1.2.2", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.2.tgz", + "integrity": "sha512-t97w3zi5Kn/LEWGA6D9qxoO0LBOG+lK2FjlEdCwDQatffB/+vYrzZ/CLYVQSoyFZAlsDoBasVoYSWZK1n39aHA==", + "dev": true, + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2" + } + }, + "web3-providers-ws": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.2.tgz", + "integrity": "sha512-Wb1mrWTGMTXOpJkL0yGvL/WYLt8fUIXx8k/l52QB2IiKzvyd42dTWn4+j8IKXGSYYzOm7NMqv6nhA5VDk12VfA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" + } + }, + "web3-shh": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.2.tgz", + "integrity": "sha512-og258NPhlBn8yYrDWjoWBBb6zo1OlBgoWGT+LL5/LPqRbjPe09hlOYHgscAAr9zZGtohTOty7RrxYw6Z6oDWCg==", + "dev": true, + "requires": { + "web3-core": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-net": "1.2.2" + } + }, + "web3-utils": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.2.tgz", + "integrity": "sha512-joF+s3243TY5cL7Z7y4h1JsJpUCf/kmFmj+eJar7Y2yNIGVcW961VyrAms75tjUysSuHaUQ3eQXjBEUJueT52A==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + } + } + }, + "@resolver-engine/core": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@resolver-engine/core/-/core-0.2.1.tgz", + "integrity": "sha512-nsLQHmPJ77QuifqsIvqjaF5B9aHnDzJjp73Q1z6apY3e9nqYrx4Dtowhpsf7Jwftg/XzVDEMQC+OzUBNTS+S1A==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "request": "^2.85.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@resolver-engine/fs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@resolver-engine/fs/-/fs-0.2.1.tgz", + "integrity": "sha512-7kJInM1Qo2LJcKyDhuYzh9ZWd+mal/fynfL9BNjWOiTcOpX+jNfqb/UmGUqros5pceBITlWGqS4lU709yHFUbg==", + "dev": true, + "requires": { + "@resolver-engine/core": "^0.2.1", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@resolver-engine/imports": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@resolver-engine/imports/-/imports-0.2.2.tgz", + "integrity": "sha512-u5/HUkvo8q34AA+hnxxqqXGfby5swnH0Myw91o3Sm2TETJlNKXibFGSKBavAH+wvWdBi4Z5gS2Odu0PowgVOUg==", + "dev": true, + "requires": { + "@resolver-engine/core": "^0.2.1", + "debug": "^3.1.0", + "hosted-git-info": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@resolver-engine/imports-fs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@resolver-engine/imports-fs/-/imports-fs-0.2.2.tgz", + "integrity": "sha512-gFCgMvCwyppjwq0UzIjde/WI+yDs3oatJhozG9xdjJdewwtd7LiF0T5i9lrHAUtqrQbqoFE4E+ZMRVHWpWHpKQ==", + "dev": true, + "requires": { + "@resolver-engine/fs": "^0.2.1", + "@resolver-engine/imports": "^0.2.2", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "@rsksmart/erc677": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@rsksmart/erc677/-/erc677-1.0.2.tgz", @@ -3469,6 +4078,12 @@ "type-detect": "4.0.8" } }, + "@solidity-parser/parser": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.6.1.tgz", + "integrity": "sha512-MUA5kP9LdeTILeOsaz/k/qA4MdTNUxrn6q6HMYsMzQN5crU9bWKND2DaoWZhzofQM0VaTOaD8GFkCw1BYbNj5w==", + "dev": true + }, "@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", @@ -4632,9 +5247,9 @@ } }, "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.8.tgz", + "integrity": "sha512-KXBiQG2OXvaPWFPDS1rD8yV9vO0OuWIqAEqLsbfX0oU2REN5KuoMnZ1gClWcBhO5I3n6oTVAmrMufOvRqdmFTQ==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -4664,9 +5279,9 @@ } }, "@types/babel__traverse": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.8.tgz", - "integrity": "sha512-yGeB2dHEdvxjP0y4UbRtQaSkXJ9649fYCmIdRoul5kfAoGCwxuCbMhag0k3RPfnuh9kPGm8x89btcfDEXdVWGw==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.12.tgz", + "integrity": "sha512-t4CoEokHTfcyfb4hUaF9oOHu9RmmNWnm1CP0YmMqOOfClKascOmvlEM736vlqeScuGvBDsHkf8R2INd4DWreQA==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -4680,6 +5295,15 @@ "@types/node": "*" } }, + "@types/cbor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-2.0.0.tgz", + "integrity": "sha1-xievwu4i8j8jN/7LNGKKT5fGr7s=", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -4692,6 +5316,15 @@ "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", "dev": true }, + "@types/graceful-fs": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz", + "integrity": "sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", @@ -5602,6 +6235,24 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" }, + "axios": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "dev": true, + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + } + } + }, "axobject-query": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.1.2.tgz", @@ -5846,20 +6497,57 @@ } }, "babel-jest": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.1.0.tgz", - "integrity": "sha512-tz0VxUhhOE2y+g8R2oFrO/2VtVjA1lkJeavlhExuRBg3LdNJY9gwQ+Vcvqt9+cqy71MCTJhewvTB7Qtnnr9SWg==", + "version": "25.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.5.1.tgz", + "integrity": "sha512-9dA9+GmMjIzgPnYtkhBg73gOo/RHqPmLruP3BaGL4KEX3Dwz6pI8auSN8G8+iuEG90+GSswyKvslN+JYSaacaQ==", "dev": true, "requires": { - "@jest/transform": "^25.1.0", - "@jest/types": "^25.1.0", - "@types/babel__core": "^7.1.0", + "@jest/transform": "^25.5.1", + "@jest/types": "^25.5.0", + "@types/babel__core": "^7.1.7", "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^25.1.0", + "babel-preset-jest": "^25.5.0", "chalk": "^3.0.0", + "graceful-fs": "^4.2.4", "slash": "^3.0.0" }, "dependencies": { + "@jest/transform": { + "version": "25.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-25.5.1.tgz", + "integrity": "sha512-Y8CEoVwXb4QwA6Y/9uDkn0Xfz0finGkieuV0xkdF9UtZGJeLukD5nLkaVrVsODB1ojRWlaoD0AJZpVHCSnJEvg==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^25.5.0", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^3.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^25.5.1", + "jest-regex-util": "^25.2.6", + "jest-util": "^25.5.0", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "realpath-native": "^2.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", + "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -5895,12 +6583,98 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "jest-haste-map": { + "version": "25.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.5.1.tgz", + "integrity": "sha512-dddgh9UZjV7SCDQUrQ+5t9yy8iEgKc1AKqZR9YDww8xsVOtzPQSMVLDChc21+g29oTRexb9/B0bIlZL+sWmvAQ==", + "dev": true, + "requires": { + "@jest/types": "^25.5.0", + "@types/graceful-fs": "^4.1.2", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.4", + "jest-serializer": "^25.5.0", + "jest-util": "^25.5.0", + "jest-worker": "^25.5.0", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7", + "which": "^2.0.2" + } + }, + "jest-regex-util": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz", + "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==", + "dev": true + }, + "jest-serializer": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.5.0.tgz", + "integrity": "sha512-LxD8fY1lByomEPflwur9o4e2a5twSQ7TaVNLlFUuToIdoJuBt8tzHfCsZ42Ok6LkKXWzFWf3AGmheuLAA7LcCA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4" + } + }, + "jest-util": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.5.0.tgz", + "integrity": "sha512-KVlX+WWg1zUTB9ktvhsg2PXZVdkI1NBevOJSkTKYAyXyH4QSvh+Lay/e/v+bmaFfrkfx43xD8QTfgobzlEXdIA==", + "dev": true, + "requires": { + "@jest/types": "^25.5.0", + "chalk": "^3.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "make-dir": "^3.0.0" + } + }, + "jest-worker": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", + "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "realpath-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-2.0.0.tgz", + "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -5909,6 +6683,15 @@ "requires": { "has-flag": "^4.0.0" } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, @@ -5960,11 +6743,13 @@ } }, "babel-plugin-jest-hoist": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.1.0.tgz", - "integrity": "sha512-oIsopO41vW4YFZ9yNYoLQATnnN46lp+MZ6H4VvPKFkcc2/fkl3CfE/NZZSmnEIEsJRmJAgkVEK0R7Zbl50CpTw==", + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.5.0.tgz", + "integrity": "sha512-u+/W+WAjMlvoocYGTwthAiQSxDcJAyHpQ6oWlHdFZaaN+Rlk8Q7iiwDPg2lN/FyJtAYnKjFxbn7xus4HCFkg5g==", "dev": true, "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", "@types/babel__traverse": "^7.0.6" } }, @@ -6274,6 +7059,24 @@ "babel-types": "^6.24.1" } }, + "babel-preset-current-node-syntax": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz", + "integrity": "sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, "babel-preset-env": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", @@ -6328,14 +7131,13 @@ } }, "babel-preset-jest": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.1.0.tgz", - "integrity": "sha512-eCGn64olaqwUMaugXsTtGAM2I0QTahjEtnRu0ql8Ie+gDWAc1N6wqN0k2NilnyTunM69Pad7gJY7LOtwLimoFQ==", + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.5.0.tgz", + "integrity": "sha512-8ZczygctQkBU+63DtSOKGh7tFL0CeCuz+1ieud9lJ1WPQ9O6A1a/r+LGn6Y705PA6whHQ3T1XuB/PmpfNYf8Fw==", "dev": true, "requires": { - "@babel/plugin-syntax-bigint": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^25.1.0" + "babel-plugin-jest-hoist": "^25.5.0", + "babel-preset-current-node-syntax": "^0.1.2" } }, "babel-register": { @@ -6542,6 +7344,16 @@ "tweetnacl": "^0.14.3" } }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==" + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -6594,6 +7406,11 @@ "safe-buffer": "^5.1.1" } }, + "blakejs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", + "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=" + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -6785,9 +7602,9 @@ } }, "buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -6967,6 +7784,26 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "cbor": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-4.3.0.tgz", + "integrity": "sha512-CvzaxQlaJVa88sdtTWvLJ++MbdtPHtZOBBNjm7h3YKUHILMs9nQyD4AC6hvFZy7GBVB3I6bRibJcxeHydyT2IQ==", + "dev": true, + "requires": { + "bignumber.js": "^9.0.0", + "commander": "^3.0.0", + "json-text-sequence": "^0.1", + "nofilter": "^1.0.3" + }, + "dependencies": { + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + } + } + }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -7739,6 +8576,38 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "requires": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "multicodec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.1.tgz", + "integrity": "sha512-yrrU/K8zHyAH2B0slNVeq3AiwluflHpgQ3TAzwNJcuO2AoPyXgBT2EDkdbP1D8B/yFOY+S2hDYmFlI1vhVFkQw==", + "requires": { + "buffer": "^5.5.0", + "varint": "^5.0.0" + } + } + } + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -7748,6 +8617,11 @@ "safe-buffer": "^5.0.1" } }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -7960,6 +8834,16 @@ } } }, + "content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "requires": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -8138,6 +9022,30 @@ } } }, + "crypto-addr-codec": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.7.tgz", + "integrity": "sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==", + "requires": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + }, + "dependencies": { + "base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "requires": { + "safe-buffer": "^5.0.1" + } + } + } + }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -8428,6 +9336,12 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "delimit-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", + "integrity": "sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs=", + "dev": true + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -10974,6 +11888,26 @@ "readable-stream": "^2.3.6" } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -28599,6 +29533,15 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, + "json-text-sequence": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", + "integrity": "sha1-py8hfcSvxGKf/1/rME3BvVGi89I=", + "dev": true, + "requires": { + "delimit-stream": "0.1.0" + } + }, "json5": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.2.tgz", @@ -29440,6 +30383,80 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + }, + "dependencies": { + "base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, + "multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "requires": { + "varint": "^5.0.0" + } + }, + "multihashes": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.19.tgz", + "integrity": "sha512-ej74GAfA20imjj00RO5h34aY3pGUFyzn9FJZFWwdeUHlHTkKmv90FrNpvYT4jYf1XXCy5O/5EjVnxTaESgOM6A==", + "requires": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + }, + "dependencies": { + "base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -29599,6 +30616,12 @@ "semver": "^6.3.0" } }, + "nofilter": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.3.tgz", + "integrity": "sha512-FlUlqwRK6reQCaFLAhMcF+6VkVG2caYjKQY3YsRDTl4/SEch595Qb3oLjJRDr8dkHAAOVj2pOx3VknfnSgkE5g==", + "dev": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -31062,6 +32085,11 @@ "inherits": "^2.0.1" } }, + "ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==" + }, "rlp": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.4.tgz", @@ -31506,6 +32534,25 @@ "safe-buffer": "^5.0.1" } }, + "sha3": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.2.tgz", + "integrity": "sha512-agYUtkzMsdFTQkM3ECyt6YW0552fyEb0tYZkl7olurS1Vg2Ms5+2SdF4VFPC1jnwtiXMb8b0fSyuAGZh+q2mAw==", + "requires": { + "buffer": "5.5.0" + }, + "dependencies": { + "buffer": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz", + "integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -32837,6 +33884,17 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" }, + "spinnies": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/spinnies/-/spinnies-0.4.3.tgz", + "integrity": "sha512-TTA2vWXrXJpfThWAl2t2hchBnCMI1JM5Wmb2uyI7Zkefdw/xO98LDy6/SBYwQPiYXL3swx3Eb44ZxgoS8X5wpA==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -33626,6 +34684,76 @@ } } }, + "truffle-flattener": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/truffle-flattener/-/truffle-flattener-1.4.4.tgz", + "integrity": "sha512-S/WmvubzlUj1mn56wEI6yo1bmPpKDNdEe5rtyVC1C5iNfZWobD/V69pAYI15IBDJrDqUyh+iXgpTkzov50zpQw==", + "dev": true, + "requires": { + "@resolver-engine/imports-fs": "^0.2.2", + "@solidity-parser/parser": "^0.6.0", + "find-up": "^2.1.0", + "mkdirp": "^1.0.4", + "tsort": "0.0.1" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, "try-require": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/try-require/-/try-require-1.2.1.tgz", @@ -33709,6 +34837,12 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, + "tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha1-4igPXoF/i/QnVlf9D5rr1E9aJ4Y=", + "dev": true + }, "tsutils": { "version": "3.17.1", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", @@ -34118,6 +35252,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "varint": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", + "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 8706f98..516f454 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rsksmart/rns", - "version": "1.7.4", + "version": "1.8.0", "description": "RIF Name Service library.", "keywords": [ "rsk", @@ -34,11 +34,14 @@ "prepublishOnly": "npm test && npm run build && cp -r lib/types/ types/" }, "dependencies": { + "@ensdomains/address-encoder": "^0.1.7", "@rsksmart/rns-registry": "^1.0.2", "@rsksmart/rns-resolver": "^1.0.2", "@rsksmart/rns-reverse": "^1.0.2", "@rsksmart/rns-rskregistrar": "^1.2.1", "@rsksmart/rsk3": "^0.3.4", + "buffer": "^5.6.0", + "content-hash": "^2.5.2", "eth-ens-namehash": "^2.0.8", "js-sha3": "^0.8.0", "rskjs-util": "^1.0.3", @@ -55,6 +58,7 @@ "@babel/preset-typescript": "^7.8.3", "@openzeppelin/test-environment": "^0.1.3", "@openzeppelin/test-helpers": "^0.5.5", + "@openzeppelin/upgrades": "^2.8.0", "@rsksmart/erc677": "^1.0.2", "@rsksmart/rns-auction-registrar": "^1.0.2", "@types/jest": "^25.1.0", diff --git a/src/@types/content-hash/index.d.ts b/src/@types/content-hash/index.d.ts new file mode 100644 index 0000000..9d6b386 --- /dev/null +++ b/src/@types/content-hash/index.d.ts @@ -0,0 +1 @@ +declare module 'content-hash'; diff --git a/src/constants.ts b/src/constants.ts index 6f55253..dc82bde 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,6 +6,8 @@ export const ADDR_INTERFACE = '0x3b3b57de'; export const SET_ADDR_INTERFACE = '0xd5fa2b00'; export const CHAIN_ADDR_INTERFACE = '0x8be4b5f6'; export const SET_CHAIN_ADDR_INTERFACE = '0xd278b400'; +export const NEW_ADDR_INTERFACE = '0xf1cb7e06'; +export const CONTENTHASH_INTERFACE = '0xbc1c58d1'; export const NAME_INTERFACE = '0x691f3431'; export const SET_NAME_INTERFACE = '0xc47f0027'; export const AVAILABLE_INTERFACE = '0x96e494e8'; diff --git a/src/contenthash-helper.ts b/src/contenthash-helper.ts new file mode 100644 index 0000000..601c838 --- /dev/null +++ b/src/contenthash-helper.ts @@ -0,0 +1,74 @@ +// most of te code has been copied from https://github.com/ensdomains/ui/blob/b7d36a2a96f6c991a8e109f91f9bd6fb6b1f4589/src/utils/contents.js +import contentHash from 'content-hash'; +import ErrorWrapper from './errors/ErrorWrapper'; +import { Options } from './types'; +import { UNSUPPORTED_CONTENTHASH_PROTOCOL } from './errors'; + +export default class extends ErrorWrapper { + constructor(options?: Options) { + super(options && options.lang); + } + + decodeContenthash(encoded: string) { + let decoded = ''; + let protocolType = ''; + + try { + decoded = contentHash.decode(encoded); + const codec = contentHash.getCodec(encoded); + if (codec === 'ipfs-ns') { + protocolType = 'ipfs'; + } else if (codec === 'swarm-ns') { + protocolType = 'bzz'; + } else if (codec === 'onion') { + protocolType = 'onion'; + } else if (codec === 'onion3') { + protocolType = 'onion3'; + } else { + this._throw(UNSUPPORTED_CONTENTHASH_PROTOCOL); + } + } catch (e) { + this._throw(UNSUPPORTED_CONTENTHASH_PROTOCOL); + } + + return { decoded, protocolType }; + } + + encodeContenthash(text: string): string { + let content = ''; + let contentType = ''; + if (text) { + const matched = text.match(/^(ipfs|bzz|onion|onion3):\/\/(.*)/) + || text.match(/\/(ipfs)\/(.*)/); + if (matched) { + ([, contentType, content] = matched); + } + + try { + if (contentType === 'ipfs') { + if (content.length >= 4) { + return `0x${contentHash.fromIpfs(content)}`; + } + } else if (contentType === 'bzz') { + if (content.length >= 4) { + return `0x${contentHash.fromSwarm(content)}`; + } + } else if (contentType === 'onion') { + if (content.length === 16) { + return `0x${contentHash.encode('onion', content)}`; + } + } else if (contentType === 'onion3') { + if (content.length === 56) { + return `0x${contentHash.encode('onion3', content)}`; + } + } else { + this._throw(UNSUPPORTED_CONTENTHASH_PROTOCOL); + } + } catch (err) { + this._throw(UNSUPPORTED_CONTENTHASH_PROTOCOL); + } + } + + return ''; + } +} diff --git a/src/errors/errors.json b/src/errors/errors.json index 4902643..1b6d54d 100644 --- a/src/errors/errors.json +++ b/src/errors/errors.json @@ -286,5 +286,41 @@ "ru": "Resolver не реализует setChainAddr метод", "zh": "解析器未实施setChainAddr方法" } + }, + "UNSUPPORTED_CONTENTHASH_PROTOCOL": { + "id": "KB025", + "message": { + "en": "The contenthash protocol is not supported", + "es": "", + "ja": "", + "ko": "", + "pt": "", + "ru": "", + "zh": "" + } + }, + "NO_CONTENTHASH_SET": { + "id": "KB026", + "message": { + "en": "No contenthash resolution set", + "es": "", + "ja": "", + "ko": "", + "pt": "", + "ru": "", + "zh": "" + } + }, + "NO_CONTENTHASH_INTERFACE": { + "id": "KB026", + "message": { + "en": "No contenthash interface", + "es": "", + "ja": "", + "ko": "", + "pt": "", + "ru": "", + "zh": "" + } } -} \ No newline at end of file +} diff --git a/src/errors/index.ts b/src/errors/index.ts index 693fdeb..0119595 100644 --- a/src/errors/index.ts +++ b/src/errors/index.ts @@ -27,3 +27,6 @@ export const NO_AVAILABLE_METHOD = 'NO_AVAILABLE_METHOD'; export const NO_REVERSE_REGISTRAR = 'NO_REVERSE_REGISTRAR'; export const NO_SET_NAME_METHOD = 'NO_SET_NAME_METHOD'; export const NO_SET_CHAIN_ADDR = 'NO_SET_CHAIN_ADDR'; +export const NO_CONTENTHASH_INTERFACE = 'NO_CONTENTHASH_INTERFACE'; +export const UNSUPPORTED_CONTENTHASH_PROTOCOL = 'UNSUPPORTED_CONTENTHASH_PROTOCOL'; +export const NO_CONTENTHASH_SET = 'NO_CONTENTHASH_SET'; diff --git a/src/factories/index.ts b/src/factories/index.ts index 3cf5fb8..0d6e6eb 100644 --- a/src/factories/index.ts +++ b/src/factories/index.ts @@ -1,11 +1,12 @@ import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; -import ChainAddrResolverData from '@rsksmart/rns-resolver/ChainAddrResolverData.json'; -import NameResolverData from '@rsksmart/rns-reverse/NameResolverData.json'; -import ReverseRegistrarData from '@rsksmart/rns-reverse/ReverseRegistrarData.json'; -import RSKOwnerData from '@rsksmart/rns-rskregistrar/RSKOwnerData.json'; +import { abi as AddrAbi } from '@rsksmart/rns-resolver/AddrResolverData.json'; +import { abi as ChainAddrAbi } from '@rsksmart/rns-resolver/ChainAddrResolverData.json'; +import { abi as NameResolverAbi } from '@rsksmart/rns-reverse/NameResolverData.json'; +import { abi as ReverseRegistrarAbi } from '@rsksmart/rns-reverse/ReverseRegistrarData.json'; +import { abi as RSKOwnerAbi } from '@rsksmart/rns-rskregistrar/RSKOwnerData.json'; import Web3 from 'web3'; import { AbiItem } from 'web3-utils'; +import { abi as ResolverV1Abi } from '../resolvers/ResolverV1Data.json'; import { NetworkId, ContractAddresses } from '../types'; import RNSError, { NO_ADDRESSES_PROVIDED } from '../errors'; @@ -30,20 +31,24 @@ export const createRegistry = ( export const createAddrResolver = ( web3: Web3, address: string, -) => new web3.eth.Contract(AddrResolverData.abi as AbiItem[], address); +) => new web3.eth.Contract(AddrAbi as AbiItem[], address); export const createChainAddrResolver = ( web3: Web3, address: string, -) => new web3.eth.Contract(ChainAddrResolverData.abi as AbiItem[], address); +) => new web3.eth.Contract(ChainAddrAbi as AbiItem[], address); + +export const createNewAddrResolver = ( + web3: Web3, address: string, +) => new web3.eth.Contract(ResolverV1Abi as AbiItem[], address); export const createNameResolver = ( web3: Web3, address: string, -) => new web3.eth.Contract(NameResolverData.abi as AbiItem[], address); +) => new web3.eth.Contract(NameResolverAbi as AbiItem[], address); export const createRskOwner = ( web3: Web3, address: string, -) => new web3.eth.Contract(RSKOwnerData.abi as AbiItem[], address); +) => new web3.eth.Contract(RSKOwnerAbi as AbiItem[], address); export const createReverseRegistrar = ( web3: Web3, address: string, -) => new web3.eth.Contract(ReverseRegistrarData.abi as AbiItem[], address); +) => new web3.eth.Contract(ReverseRegistrarAbi as AbiItem[], address); diff --git a/src/index.ts b/src/index.ts index d90e6d0..5cde2b2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ import Subdomains from './subdomains'; import Composer from './composer'; import * as utils from './utils'; import { TransactionOptions } from './types/options'; +import { DecodedContenthash } from './types/resolutions'; /** * RNS JavaScript library. @@ -102,6 +103,30 @@ export default class extends Composer implements RNS { return this._resolutions.setChainAddr(domain, addr, chainId, options); } + /** + * Get decoded contenthash of a given domain. + * + * @param domain - Domain to be resolved + * + * @returns + * Decoded content and protocolType associated to the given domain + */ + contenthash(domain: string): Promise { + return this._resolutions.contenthash(domain); + } + + /** + * Set contenthash of a given domain. + * + * @param domain - Domain to be resolved + * @param content - Content to be associated to the given domain. Must be decoded, the library will encode and save it. + * + * @returns TransactionReceipt of the submitted tx + */ + setContenthash(domain: string, content: string, options?: TransactionOptions): any { + return this._resolutions.setContenthash(domain, content, options); + } + /** * Set resolver of a given domain. * diff --git a/src/resolutions.ts b/src/resolutions.ts index b6c17f0..f5e1ff6 100644 --- a/src/resolutions.ts +++ b/src/resolutions.ts @@ -1,13 +1,15 @@ import Web3 from 'web3'; import { Contract } from 'web3-eth-contract'; import { TransactionReceipt } from 'web3-eth'; +import { formatsByCoinType } from '@ensdomains/address-encoder'; import { - createAddrResolver, createChainAddrResolver, createNameResolver, createReverseRegistrar, + createAddrResolver, createChainAddrResolver, createNameResolver, + createReverseRegistrar, createNewAddrResolver, } from './factories'; import { ZERO_ADDRESS, ADDR_INTERFACE, SET_CHAIN_ADDR_INTERFACE, CHAIN_ADDR_INTERFACE, NAME_INTERFACE, ADDR_REVERSE_NAMEHASH, - SET_NAME_INTERFACE, SET_ADDR_INTERFACE, + SET_NAME_INTERFACE, NEW_ADDR_INTERFACE, CONTENTHASH_INTERFACE, } from './constants'; import { ChainId, Resolutions, Options, NetworkId, @@ -20,15 +22,21 @@ import { import { NO_RESOLVER, NO_ADDR_RESOLUTION, NO_ADDR_RESOLUTION_SET, NO_CHAIN_ADDR_RESOLUTION, NO_CHAIN_ADDR_RESOLUTION_SET, NO_NAME_RESOLUTION, NO_REVERSE_RESOLUTION_SET, - NO_ACCOUNTS_TO_SIGN, NO_SET_ADDR, INVALID_ADDRESS, INVALID_CHECKSUM_ADDRESS, - DOMAIN_NOT_EXISTS, INVALID_DOMAIN, NO_REVERSE_REGISTRAR, NO_SET_NAME_METHOD, NO_SET_CHAIN_ADDR, + NO_ACCOUNTS_TO_SIGN, INVALID_ADDRESS, INVALID_CHECKSUM_ADDRESS, + DOMAIN_NOT_EXISTS, INVALID_DOMAIN, NO_REVERSE_REGISTRAR, NO_SET_NAME_METHOD, + NO_CONTENTHASH_INTERFACE, NO_CONTENTHASH_SET, UNSUPPORTED_CONTENTHASH_PROTOCOL, } from './errors'; import { TransactionOptions } from './types/options'; +import { CoinType } from './types/enums'; +import ContenthashHelper from './contenthash-helper'; +import { DecodedContenthash } from './types/resolutions'; /** * Standard resolution protocols. */ export default class extends Composer implements Resolutions { + _contenthashHelper: ContenthashHelper; + /** * * @param blockchainApi - current Web3 or Rsk3 instance @@ -36,6 +44,7 @@ export default class extends Composer implements Resolutions { */ constructor(public blockchainApi: Web3 | any, options?: Options) { super(blockchainApi, options); + this._contenthashHelper = new ContenthashHelper(options); } /** @@ -52,8 +61,6 @@ export default class extends Composer implements Resolutions { */ private async _createResolver( node: string, - methodInterface: string, - errorMessage: string, contractFactory: (blockchainApi: Web3 | any, address: string) => Contract, noResolverError?: string, ): Promise { @@ -65,14 +72,6 @@ export default class extends Composer implements Resolutions { const resolver: Contract = contractFactory(this.blockchainApi, resolverAddress); - const supportsInterface: boolean = await hasMethod( - this.blockchainApi, resolverAddress, methodInterface, - ); - - if (!supportsInterface) { - this._throw(errorMessage); - } - return resolver; } @@ -98,6 +97,20 @@ export default class extends Composer implements Resolutions { } } + _getCoinTypeFromChainId(chainId: ChainId): number { + switch (chainId) { + case ChainId.BITCOIN: + return CoinType.BITCOIN; + case ChainId.ETHEREUM: + return CoinType.ETHEREUM; + case ChainId.LITECOIN: + return CoinType.LITECOIN; + case ChainId.RSK: + default: + return CoinType.RSK; + } + } + /** * addr resolution protocol. @@ -114,12 +127,15 @@ export default class extends Composer implements Resolutions { await this.compose(); const node: string = namehash(domain); - const resolver = await this._createResolver( - node, + const resolver = await this._createResolver(node, createAddrResolver); + + const supportsInterface: boolean = await resolver.methods.supportsInterface( ADDR_INTERFACE, - NO_ADDR_RESOLUTION, - createAddrResolver, - ); + ).call(); + + if (!supportsInterface) { + this._throw(NO_ADDR_RESOLUTION); + } const addr: string = await resolver.methods.addr(node).call(); @@ -147,14 +163,43 @@ export default class extends Composer implements Resolutions { await this.compose(); const node: string = namehash(domain); - const resolver = await this._createResolver( - node, + const newResolver = await this._createResolver(node, createNewAddrResolver); + + const supportsNewAddrInterface: boolean = await newResolver.methods.supportsInterface( + NEW_ADDR_INTERFACE, + ).call(); + + if (supportsNewAddrInterface) { + const coinType = this._getCoinTypeFromChainId(chainId); + const decodedAddr = await newResolver.methods['addr(bytes32,uint256)'](node, coinType).call(); + + if (!decodedAddr || decodedAddr === ZERO_ADDRESS || decodedAddr === '0x') { + this._throw(NO_CHAIN_ADDR_RESOLUTION_SET); + } + + const buff = Buffer.from(decodedAddr.replace('0x', ''), 'hex'); + + const addr = formatsByCoinType[coinType].encoder(buff); + + if (!addr || addr === ZERO_ADDRESS) { + this._throw(NO_CHAIN_ADDR_RESOLUTION_SET); + } + + return addr; + } + + const chainResolver = await this._createResolver(node, createChainAddrResolver); + + const supportsChainAddrInterface: boolean = await chainResolver.methods.supportsInterface( CHAIN_ADDR_INTERFACE, - NO_CHAIN_ADDR_RESOLUTION, - createChainAddrResolver, - ); + ).call(); + + if (!supportsChainAddrInterface) { + this._throw(NO_CHAIN_ADDR_RESOLUTION); + } + + const addr = await chainResolver.methods.chainAddr(node, chainId).call(); - const addr: string = await resolver.methods.chainAddr(node, chainId).call(); if (!addr || addr === ZERO_ADDRESS) { this._throw(NO_CHAIN_ADDR_RESOLUTION_SET); } @@ -198,12 +243,7 @@ export default class extends Composer implements Resolutions { const node: string = namehash(domain); - const resolver = await this._createResolver( - node, - SET_ADDR_INTERFACE, - NO_SET_ADDR, - createAddrResolver, - ); + const resolver = await this._createResolver(node, createAddrResolver); const contractMethod = resolver.methods.setAddr(node, addr); @@ -239,20 +279,96 @@ export default class extends Composer implements Resolutions { const node: string = namehash(domain); - const resolver = await this._createResolver( - node, - SET_CHAIN_ADDR_INTERFACE, - NO_SET_CHAIN_ADDR, - createChainAddrResolver, + const resolverAddress: string = await this._contracts.registry.methods.resolver(node).call(); + + if (resolverAddress === ZERO_ADDRESS) { + this._throw(NO_RESOLVER); + } + + const supportsChainAddrInterface: boolean = await hasMethod( + this.blockchainApi, resolverAddress, SET_CHAIN_ADDR_INTERFACE, ); - const contractMethod = resolver - .methods - .setChainAddr( - node, - chainId, - addr, - ); + let contractMethod; + if (supportsChainAddrInterface) { + const resolver: Contract = createChainAddrResolver(this.blockchainApi, resolverAddress); + + contractMethod = resolver.methods.setChainAddr(node, chainId, addr); + } else { + const resolver: Contract = createNewAddrResolver(this.blockchainApi, resolverAddress); + + const coinType = this._getCoinTypeFromChainId(chainId); + + const decodedAddr = addr ? formatsByCoinType[coinType].decoder(addr) : '0x'; + + contractMethod = resolver.methods['setAddr(bytes32,uint256,bytes)'](node, coinType, decodedAddr); + } + + return this.estimateGasAndSendTransaction(contractMethod, options); + } + + /** + * Get decoded contenthash of a given domain. + * + * @param domain - Domain to be resolved + * + * @return + * Decoded contenthash associated to the given domain + */ + async contenthash(domain: string): Promise { + await this.compose(); + const node: string = namehash(domain); + + const resolver = await this._createResolver(node, createNewAddrResolver); + + const supportsInterface: boolean = await resolver.methods.supportsInterface( + CONTENTHASH_INTERFACE, + ).call(); + + if (!supportsInterface) { + this._throw(NO_CONTENTHASH_INTERFACE); + } + + const encoded: string = await resolver.methods.contenthash(node).call(); + + if (!encoded || encoded === '0x') { + this._throw(NO_CONTENTHASH_SET); + } + + const decoded = this._contenthashHelper.decodeContenthash(encoded); + + if (!decoded?.protocolType) { + this._throw(UNSUPPORTED_CONTENTHASH_PROTOCOL); + } + + return decoded!; + } + + /** + * Set contenthash of a given domain. + * + * @param domain - Domain to be resolved + * @param content - Content to be associated to the given domain. Must be decoded, the library will encode and save it. + * + * @return + * TransactionReceipt of the submitted tx + */ + async setContenthash( + domain: string, content: string, options?: TransactionOptions, + ): Promise { + await this.compose(); + + if (!await hasAccounts(this.blockchainApi)) { + this._throw(NO_ACCOUNTS_TO_SIGN); + } + + const node: string = namehash(domain); + + const resolver = await this._createResolver(node, createNewAddrResolver); + + const encodedContenthash = content ? this._contenthashHelper.encodeContenthash(content) : '0x'; + + const contractMethod = resolver.methods['setContenthash(bytes32,bytes)'](node, encodedContenthash); return this.estimateGasAndSendTransaction(contractMethod, options); } @@ -360,12 +476,18 @@ export default class extends Composer implements Resolutions { const resolver = await this._createResolver( node, - NAME_INTERFACE, - NO_NAME_RESOLUTION, createNameResolver, NO_REVERSE_RESOLUTION_SET, ); + const supportsInterface: boolean = await resolver.methods.supportsInterface( + NAME_INTERFACE, + ).call(); + + if (!supportsInterface) { + this._throw(NO_NAME_RESOLUTION); + } + const name: string = await resolver.methods.name(node).call(); if (!name) { this._throw(NO_REVERSE_RESOLUTION_SET); diff --git a/src/resolvers/ProxyAdminData.json b/src/resolvers/ProxyAdminData.json new file mode 100644 index 0000000..1f7be38 --- /dev/null +++ b/src/resolvers/ProxyAdminData.json @@ -0,0 +1 @@ +{"abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"contract AdminUpgradeabilityProxy","name":"proxy","type":"address"}],"name":"getProxyImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract AdminUpgradeabilityProxy","name":"proxy","type":"address"}],"name":"getProxyAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract AdminUpgradeabilityProxy","name":"proxy","type":"address"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"changeProxyAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract AdminUpgradeabilityProxy","name":"proxy","type":"address"},{"internalType":"address","name":"implementation","type":"address"}],"name":"upgrade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract AdminUpgradeabilityProxy","name":"proxy","type":"address"},{"internalType":"address","name":"implementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeAndCall","outputs":[],"payable":true,"stateMutability":"payable","type":"function"}],"bytecode":"0x6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3610b15806100cf6000396000f3fe6080604052600436106100865760003560e01c80638f32d59b116100595780638f32d59b146101fb5780639623609d1461022a57806399a88ec414610325578063f2fde38b14610396578063f3b7dead146103e757610086565b8063204e1c7a1461008b578063715018a61461011c5780637eff275e146101335780638da5cb5b146101a4575b600080fd5b34801561009757600080fd5b506100da600480360360208110156100ae57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610478565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561012857600080fd5b50610131610540565b005b34801561013f57600080fd5b506101a26004803603604081101561015657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610610565b005b3480156101b057600080fd5b506101b96106bc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561020757600080fd5b506102106106e5565b604051808215151515815260200191505060405180910390f35b6103236004803603606081101561024057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561029d57600080fd5b8201836020820111156102af57600080fd5b803590602001918460018302840111640100000000831117156102d157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061073c565b005b34801561033157600080fd5b506103946004803603604081101561034857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610857565b005b3480156103a257600080fd5b506103e5600480360360208110156103b957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610903565b005b3480156103f357600080fd5b506104366004803603602081101561040a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610920565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008060608373ffffffffffffffffffffffffffffffffffffffff1660405180807f5c60da1b000000000000000000000000000000000000000000000000000000008152506004019050600060405180830381855afa9150503d80600081146104fd576040519150601f19603f3d011682016040523d82523d6000602084013e610502565b606091505b50915091508161051157600080fd5b80806020019051602081101561052657600080fd5b810190808051906020019092919050505092505050919050565b6105486106e5565b61055157600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6106186106e5565b61062157600080fd5b8173ffffffffffffffffffffffffffffffffffffffff16638f283970826040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156106a057600080fd5b505af11580156106b4573d6000803e3d6000fd5b505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6107446106e5565b61074d57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff16634f1ef2863484846040518463ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156107ed5780820151818401526020810190506107d2565b50505050905090810190601f16801561081a5780820380516001836020036101000a031916815260200191505b5093505050506000604051808303818588803b15801561083957600080fd5b505af115801561084d573d6000803e3d6000fd5b5050505050505050565b61085f6106e5565b61086857600080fd5b8173ffffffffffffffffffffffffffffffffffffffff16633659cfe6826040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156108e757600080fd5b505af11580156108fb573d6000803e3d6000fd5b505050505050565b61090b6106e5565b61091457600080fd5b61091d816109e8565b50565b60008060608373ffffffffffffffffffffffffffffffffffffffff1660405180807ff851a440000000000000000000000000000000000000000000000000000000008152506004019050600060405180830381855afa9150503d80600081146109a5576040519150601f19603f3d011682016040523d82523d6000602084013e6109aa565b606091505b5091509150816109b957600080fd5b8080602001905160208110156109ce57600080fd5b810190808051906020019092919050505092505050919050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610a2257600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72315820f9fa5f4056a82fc6924be0114c6bf0ad4985b381d5d7a37a096d8f1ff1b2653264736f6c63430005100032","address":{"rskMainnet":"0x30569C0999f0C7fD7be9957ac4B4dEe803CAc293","rskTestnet":"0xbb71C17b28BAF2B9e7f5b31660eCF758113b3fEf"}} diff --git a/src/resolvers/ProxyFactoryData.json b/src/resolvers/ProxyFactoryData.json new file mode 100644 index 0000000..d651a3d --- /dev/null +++ b/src/resolvers/ProxyFactoryData.json @@ -0,0 +1,2 @@ +{"abi":[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxy","type":"address"}],"name":"ProxyCreated","type":"event"},{"constant":false,"inputs":[{"internalType":"address","name":"_logic","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"deployMinimal","outputs":[{"internalType":"address","name":"proxy","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_salt","type":"uint256"},{"internalType":"address","name":"_logic","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"deploy","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_salt","type":"uint256"},{"internalType":"address","name":"_logic","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"deploySigned","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_salt","type":"uint256"},{"internalType":"address","name":"_sender","type":"address"}],"name":"getDeploymentAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_salt","type":"uint256"},{"internalType":"address","name":"_logic","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"getSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}],"bytecode":"0x608060405234801561001057600080fd5b506040518060200161002190610047565b6020820181038252601f19601f8201166040525080519060200120600081905550610054565b610d2280611d4083390190565b611cdd806100636000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063290f8f561461005c578063332d6626146102385780636150864c1461041457806381ae1f5b14610559578063b3eeb5e2146105e7575b600080fd5b6101f6600480360360a081101561007257600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156100d957600080fd5b8201836020820111156100eb57600080fd5b8035906020019184600183028401116401000000008311171561010d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561017057600080fd5b82018360208201111561018257600080fd5b803590602001918460018302840111640100000000831117156101a457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610702565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103d2600480360360a081101561024e57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156102b557600080fd5b8201836020820111156102c757600080fd5b803590602001918460018302840111640100000000831117156102e957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561034c57600080fd5b82018360208201111561035e57600080fd5b8035906020019184600183028401116401000000008311171561038057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610844565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105176004803603608081101561042a57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561049157600080fd5b8201836020820111156104a357600080fd5b803590602001918460018302840111640100000000831117156104c557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610912565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105a56004803603604081101561056f57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061092b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6106c0600480360360408110156105fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561063a57600080fd5b82018360208201111561064c57600080fd5b8035906020019184600183028401116401000000008311171561066e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610a08565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008061082c8787878730604051602001808681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140183805190602001908083835b602083106107b35780518252602082019150602081019050602083039250610790565b6001836020036101000a0380198251168184511680821785525050505050509050018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014019550505050505060405160208183030381529060405280519060200120610ba3565b90506108388184610bfb565b91505095945050505050565b6000806108548787878787610702565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156108f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f496e76616c6964207369676e617475726500000000000000000000000000000081525060200191505060405180910390fd5b6109068787878785610cff565b91505095945050505050565b60006109218585858533610cff565b9050949350505050565b6000806109388484610eb5565b9050600060ff60f81b308360005460405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401838152602001828152602001945050505050604051602081830303815290604052805190602001209050606081901b60601c9250505092915050565b6000808360601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f09250507efffc2da0b561cae30d9826d37709e9421c4725faebc226cbbb7ef5fc5e734982604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600083511115610b9c5760008273ffffffffffffffffffffffffffffffffffffffff16846040518082805190602001908083835b60208310610b255780518252602082019150602081019050602083039250610b02565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610b87576040519150601f19603f3d011682016040523d82523d6000602084013e610b8c565b606091505b5050905080610b9a57600080fd5b505b5092915050565b60008160405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c01828152602001915050604051602081830303815290604052805190602001209050919050565b60006041825114610c0f5760009050610cf9565b60008060006020850151925060408501519150606085015160001a90507f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08260001c1115610c635760009350505050610cf9565b601b8160ff1614158015610c7b5750601c8160ff1614155b15610c8c5760009350505050610cf9565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610ce9573d6000803e3d6000fd5b5050506020604051035193505050505b92915050565b600080610d0c8784610f1d565b90507efffc2da0b561cae30d9826d37709e9421c4725faebc226cbbb7ef5fc5e734981604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff1663cf7a1d778787876040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610e42578082015181840152602081019050610e27565b50505050905090810190601f168015610e6f5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015610e9057600080fd5b505af1158015610ea4573d6000803e3d6000fd5b505050508091505095945050505050565b60008282604051602001808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014019250505060405160208183030381529060405280519060200120905092915050565b600080606060405180602001610f3290610f79565b6020820181038252601f19601f8201166040525090506000610f548686610eb5565b9050808251602084016000f59250823b610f6d57600080fd5b82935050505092915050565b610d2280610f878339019056fe608060405234801561001057600080fd5b50610d02806100206000396000f3fe6080604052600436106100705760003560e01c80638f2839701161004e5780638f283970146101bb578063cf7a1d771461020c578063d1f5789414610307578063f851a440146103e257610070565b80633659cfe61461007a5780634f1ef286146100cb5780635c60da1b14610164575b610078610439565b005b34801561008657600080fd5b506100c96004803603602081101561009d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610453565b005b610162600480360360408110156100e157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561011e57600080fd5b82018360208201111561013057600080fd5b8035906020019184600183028401116401000000008311171561015257600080fd5b90919293919293905050506104a8565b005b34801561017057600080fd5b5061017961057e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101c757600080fd5b5061020a600480360360208110156101de57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105d6565b005b6103056004803603606081101561022257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561027f57600080fd5b82018360208201111561029157600080fd5b803590602001918460018302840111640100000000831117156102b357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061074f565b005b6103e06004803603604081101561031d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561035a57600080fd5b82018360208201111561036c57600080fd5b8035906020019184600183028401116401000000008311171561038e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610811565b005b3480156103ee57600080fd5b506103f7610994565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104416109ec565b61045161044c610a82565b610ab3565b565b61045b610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561049c5761049781610b0a565b6104a5565b6104a4610439565b5b50565b6104b0610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610570576104ec83610b0a565b60008373ffffffffffffffffffffffffffffffffffffffff168383604051808383808284378083019250505092505050600060405180830381855af49150503d8060008114610557576040519150601f19603f3d011682016040523d82523d6000602084013e61055c565b606091505b505090508061056a57600080fd5b50610579565b610578610439565b5b505050565b6000610588610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156105ca576105c3610a82565b90506105d3565b6105d2610439565b5b90565b6105de610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561074357600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610697576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180610c5d6036913960400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6106c0610ad9565b82604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a161073e81610b59565b61074c565b61074b610439565b5b50565b600073ffffffffffffffffffffffffffffffffffffffff1661076f610a82565b73ffffffffffffffffffffffffffffffffffffffff161461078f57600080fd5b6107998382610811565b600160405180807f656970313936372e70726f78792e61646d696e000000000000000000000000008152506013019050604051809103902060001c0360001b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b1461080357fe5b61080c82610b59565b505050565b600073ffffffffffffffffffffffffffffffffffffffff16610831610a82565b73ffffffffffffffffffffffffffffffffffffffff161461085157600080fd5b600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b146108bb57fe5b6108c482610b88565b6000815111156109905760008273ffffffffffffffffffffffffffffffffffffffff16826040518082805190602001908083835b6020831061091b57805182526020820191506020810190506020830392506108f8565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461097b576040519150601f19603f3d011682016040523d82523d6000602084013e610980565b606091505b505090508061098e57600080fd5b505b5050565b600061099e610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156109e0576109d9610ad9565b90506109e9565b6109e8610439565b5b90565b6109f4610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610a78576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526032815260200180610c2b6032913960400191505060405180910390fd5b610a80610c15565b565b6000807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b9050805491505090565b3660008037600080366000845af43d6000803e8060008114610ad4573d6000f35b3d6000fd5b6000807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b9050805491505090565b610b1381610b88565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b90508181555050565b610b9181610c17565b610be6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b815260200180610c93603b913960400191505060405180910390fd5b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b90508181555050565b565b600080823b90506000811191505091905056fe43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e2066726f6d207468652070726f78792061646d696e43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f787920746f20746865207a65726f206164647265737343616e6e6f742073657420612070726f787920696d706c656d656e746174696f6e20746f2061206e6f6e2d636f6e74726163742061646472657373a265627a7a72315820a6f2dbb324575f7cf072335130e9ac1f14aae15fd84d2cc4e871baf88177287564736f6c63430005100032a265627a7a723158209e1a99187b2ed7ecfa1a2b3191c44c269bfecfea797ea8e4b940ea4dfdc6d44a64736f6c63430005100032608060405234801561001057600080fd5b50610d02806100206000396000f3fe6080604052600436106100705760003560e01c80638f2839701161004e5780638f283970146101bb578063cf7a1d771461020c578063d1f5789414610307578063f851a440146103e257610070565b80633659cfe61461007a5780634f1ef286146100cb5780635c60da1b14610164575b610078610439565b005b34801561008657600080fd5b506100c96004803603602081101561009d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610453565b005b610162600480360360408110156100e157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561011e57600080fd5b82018360208201111561013057600080fd5b8035906020019184600183028401116401000000008311171561015257600080fd5b90919293919293905050506104a8565b005b34801561017057600080fd5b5061017961057e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101c757600080fd5b5061020a600480360360208110156101de57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105d6565b005b6103056004803603606081101561022257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561027f57600080fd5b82018360208201111561029157600080fd5b803590602001918460018302840111640100000000831117156102b357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061074f565b005b6103e06004803603604081101561031d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561035a57600080fd5b82018360208201111561036c57600080fd5b8035906020019184600183028401116401000000008311171561038e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610811565b005b3480156103ee57600080fd5b506103f7610994565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104416109ec565b61045161044c610a82565b610ab3565b565b61045b610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561049c5761049781610b0a565b6104a5565b6104a4610439565b5b50565b6104b0610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610570576104ec83610b0a565b60008373ffffffffffffffffffffffffffffffffffffffff168383604051808383808284378083019250505092505050600060405180830381855af49150503d8060008114610557576040519150601f19603f3d011682016040523d82523d6000602084013e61055c565b606091505b505090508061056a57600080fd5b50610579565b610578610439565b5b505050565b6000610588610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156105ca576105c3610a82565b90506105d3565b6105d2610439565b5b90565b6105de610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561074357600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610697576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180610c5d6036913960400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6106c0610ad9565b82604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a161073e81610b59565b61074c565b61074b610439565b5b50565b600073ffffffffffffffffffffffffffffffffffffffff1661076f610a82565b73ffffffffffffffffffffffffffffffffffffffff161461078f57600080fd5b6107998382610811565b600160405180807f656970313936372e70726f78792e61646d696e000000000000000000000000008152506013019050604051809103902060001c0360001b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b1461080357fe5b61080c82610b59565b505050565b600073ffffffffffffffffffffffffffffffffffffffff16610831610a82565b73ffffffffffffffffffffffffffffffffffffffff161461085157600080fd5b600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b146108bb57fe5b6108c482610b88565b6000815111156109905760008273ffffffffffffffffffffffffffffffffffffffff16826040518082805190602001908083835b6020831061091b57805182526020820191506020810190506020830392506108f8565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461097b576040519150601f19603f3d011682016040523d82523d6000602084013e610980565b606091505b505090508061098e57600080fd5b505b5050565b600061099e610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156109e0576109d9610ad9565b90506109e9565b6109e8610439565b5b90565b6109f4610ad9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610a78576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526032815260200180610c2b6032913960400191505060405180910390fd5b610a80610c15565b565b6000807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b9050805491505090565b3660008037600080366000845af43d6000803e8060008114610ad4573d6000f35b3d6000fd5b6000807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b9050805491505090565b610b1381610b88565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b90508181555050565b610b9181610c17565b610be6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b815260200180610c93603b913960400191505060405180910390fd5b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b90508181555050565b565b600080823b90506000811191505091905056fe43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e2066726f6d207468652070726f78792061646d696e43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f787920746f20746865207a65726f206164647265737343616e6e6f742073657420612070726f787920696d706c656d656e746174696f6e20746f2061206e6f6e2d636f6e74726163742061646472657373a265627a7a72315820a6f2dbb324575f7cf072335130e9ac1f14aae15fd84d2cc4e871baf88177287564736f6c63430005100032","address":{"rskMainnet":"0xcCDBc15EdD43B15911895A5A592f7bFA43D9cfB1","rskTestnet":"0x02761E40dB981268ee80e9E5302e6df212259Fd4"}} + \ No newline at end of file diff --git a/src/resolvers/ResolverV1Data.json b/src/resolvers/ResolverV1Data.json new file mode 100644 index 0000000..b4fb005 --- /dev/null +++ b/src/resolvers/ResolverV1Data.json @@ -0,0 +1 @@ +{"abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"AuthorisationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"authorisations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"rns","outputs":[{"internalType":"contract AbstractRNS","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract AbstractRNS","name":"_rns","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"setAuthorisation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"}],"bytecode":"0x608060405234801561001057600080fd5b50612b12806100206000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063663b44c5116100ad578063c869023311610071578063c869023314610364578063d5fa2b0014610395578063e59d895d146103b1578063f1cb7e06146103cd578063f86bc879146103fd5761012c565b8063663b44c5146102ae5780638b95dd71146102cc578063ac9650d8146102e8578063bc1c58d114610318578063c4d66de8146103485761012c565b8063304e6ade116100f4578063304e6ade146101fa5780633b3b57de146102165780633e9ce7941461024657806359d1d43c14610262578063623195b0146102925761012c565b806301ffc9a71461013157806310f13a8c14610161578063124a319c1461017d5780632203ab56146101ad57806329cd62ea146101de575b600080fd5b61014b60048036036101469190810190612219565b61042d565b6040516101589190612689565b60405180910390f35b61017b60048036036101769190810190612081565b61049a565b005b61019760048036036101929190810190611f46565b610548565b6040516101a49190612616565b60405180910390f35b6101c760048036036101c2919081019061210a565b610933565b6040516101d59291906127ca565b60405180910390f35b6101f860048036036101f39190810190611ef7565b610a83565b005b610214600480360361020f9190810190611fd1565b610b15565b005b610230600480360361022b9190810190611df4565b610b8b565b60405161023d919061264c565b60405180910390f35b610260600480360361025b9190810190611ea8565b610bc2565b005b61027c60048036036102779190810190612029565b610cd2565b6040516102899190612788565b60405180910390f35b6102ac60048036036102a79190810190612146565b610da7565b005b6102b6610e35565b6040516102c39190612749565b60405180910390f35b6102e660048036036102e191908101906121b2565b610e5b565b005b61030260048036036102fd9190810190611daf565b610f31565b60405161030f9190612667565b60405180910390f35b610332600480360361032d9190810190611df4565b611087565b60405161033f9190612727565b60405180910390f35b610362600480360361035d9190810190612242565b61113c565b005b61037e60048036036103799190810190611df4565b611267565b60405161038c9291906126bf565b60405180910390f35b6103af60048036036103aa9190810190611e1d565b6112a1565b005b6103cb60048036036103c69190810190611f82565b611374565b005b6103e760048036036103e2919081019061210a565b611486565b6040516103f49190612727565b60405180910390f35b61041760048036036104129190810190611e59565b61154d565b6040516104249190612689565b60405180910390f35b600060405161043b90612601565b60405180910390207bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610493575061049282611589565b5b9050919050565b846104a4816115ea565b6104ad57600080fd5b82826037600089815260200190815260200160002087876040516104d29291906125e8565b908152602001604051809103902091906104ed929190611a1c565b5084846040516104fe9291906125e8565b6040518091039020867fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a75508787604051610538929190612764565b60405180910390a3505050505050565b600080603860008581526020019081526020016000206000847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461060d578091505061092d565b600061061885610b8b565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561065a5760009250505061092d565b600060608273ffffffffffffffffffffffffffffffffffffffff166301ffc9a760e01b60405160240161068d91906126e8565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071791906125d1565b600060405180830381855afa9150503d8060008114610752576040519150601f19603f3d011682016040523d82523d6000602084013e610757565b606091505b509150915081158061076a575060208151105b806107b15750600060f81b81601f8151811061078257fe5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b156107c357600094505050505061092d565b8273ffffffffffffffffffffffffffffffffffffffff16866040516024016107eb91906126e8565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161087591906125d1565b600060405180830381855afa9150503d80600081146108b0576040519150601f19603f3d011682016040523d82523d6000602084013e6108b5565b606091505b5080925081935050508115806108cc575060208151105b806109135750600060f81b81601f815181106108e457fe5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b1561092557600094505050505061092d565b829450505050505b92915050565b6000606060006035600086815260200190815260200160002090506000600190505b848111610a605760008582161415801561099557506000826000838152602001908152602001600020805460018160011615610100020316600290049050115b15610a545780826000838152602001908152602001600020808054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a425780601f10610a1757610100808354040283529160200191610a42565b820191906000526020600020905b815481529060010190602001808311610a2557829003601f168201915b50505050509050935093505050610a7c565b600181901b9050610955565b5060006040518060200160405280600081525081915092509250505b9250929050565b82610a8d816115ea565b610a9657600080fd5b604051806040016040528084815260200183815250603660008681526020019081526020016000206000820151816000015560208201518160010155905050837f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e468484604051610b079291906126bf565b60405180910390a250505050565b82610b1f816115ea565b610b2857600080fd5b8282603460008781526020019081526020016000209190610b4a929190611a9c565b50837fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d75788484604051610b7d929190612703565b60405180910390a250505050565b60006060610b9a836089611486565b9050600081511415610bb0576000915050610bbd565b610bb981611773565b9150505b919050565b80603a600085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16847fe1c5610a6e0cbe10764ecd182adcef1ec338dc4e199c99c32ce98f38e12791df84604051610cc59190612689565b60405180910390a4505050565b6060603760008581526020019081526020016000208383604051610cf79291906125e8565b90815260200160405180910390208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610d995780601f10610d6e57610100808354040283529160200191610d99565b820191906000526020600020905b815481529060010190602001808311610d7c57829003601f168201915b505050505090509392505050565b83610db1816115ea565b610dba57600080fd5b600084600186031614610dcc57600080fd5b82826035600088815260200190815260200160002060008781526020019081526020016000209190610dff929190611a9c565b5083857faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe360405160405180910390a35050505050565b603960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b82610e65816115ea565b610e6e57600080fd5b837f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af7528484604051610ea09291906127ca565b60405180910390a26089831415610ef257837f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2610edc84611773565b604051610ee99190612631565b60405180910390a25b816033600086815260200190815260200160002060008581526020019081526020016000209080519060200190610f2a929190611b1c565b5050505050565b606082829050604051908082528060200260200182016040528015610f6a57816020015b6060815260200190600190039081610f555790505b50905060008090505b8383905081101561107d57600060603073ffffffffffffffffffffffffffffffffffffffff16868685818110610fa557fe5b9050602002810180356001602003833603038112610fc257600080fd5b8083019250508135905060208201915067ffffffffffffffff811115610fe757600080fd5b600181023603821315610ff957600080fd5b6040516110079291906125b8565b600060405180830381855af49150503d8060008114611042576040519150601f19603f3d011682016040523d82523d6000602084013e611047565b606091505b50915091508161105657600080fd5b8084848151811061106357fe5b602002602001018190525050508080600101915050610f73565b5080905092915050565b6060603460008381526020019081526020016000208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156111305780601f1061110557610100808354040283529160200191611130565b820191906000526020600020905b81548152906001019060200180831161111357829003601f168201915b50505050509050919050565b600060019054906101000a900460ff168061115b575061115a611796565b5b8061117257506000809054906101000a900460ff16155b6111b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111a8906127aa565b60405180910390fd5b60008060019054906101000a900460ff161590508015611201576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b81603960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080156112635760008060016101000a81548160ff0219169083151502179055505b5050565b6000806036600084815260200190815260200160002060000154603660008581526020019081526020016000206001015491509150915091565b816112ab816115ea565b6112b457600080fd5b60606112bf836117ad565b9050837f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af7526089836040516112f49291906127ca565b60405180910390a2837f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd28460405161132c9190612616565b60405180910390a28060336000868152602001908152602001600020600060898152602001908152602001600020908051906020019061136d929190611b1c565b5050505050565b8261137e816115ea565b61138757600080fd5b81603860008681526020019081526020016000206000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847f7c69f06bea0bdef565b709e93a147836b0063ba2dd89f02d0b7e8d931e6a6daa846040516114789190612616565b60405180910390a350505050565b60606033600084815260200190815260200160002060008381526020019081526020016000208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156115405780601f1061151557610100808354040283529160200191611540565b820191906000526020600020905b81548152906001019060200180831161152357829003601f168201915b5050505050905092915050565b603a602052826000526040600020602052816000526040600020602052806000526040600020600092509250509054906101000a900460ff1681565b60006359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806115e357506115e2826117f8565b5b9050919050565b600080603960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166302571be3846040518263ffffffff1660e01b815260040161164891906126a4565b60206040518083038186803b15801561166057600080fd5b505afa158015611674573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116989190810190611d86565b90503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061176b5750603a600084815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b915050919050565b6000601482511461178357600080fd5b600c6101000a6020830151049050919050565b6000803090506000813b9050600081149250505090565b606060146040519080825280601f01601f1916602001820160405280156117e35781602001600182028038833980820191505090505b509050600c6101000a82026020820152919050565b600063c869023360e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611852575061185182611859565b5b9050919050565b6000632203ab5660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806118b357506118b2826118ba565b5b9050919050565b600063bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061191457506119138261191b565b5b9050919050565b6000633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806119b4575063f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806119c457506119c3826119cb565b5b9050919050565b60006301ffc9a760e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a5d57803560ff1916838001178555611a8b565b82800160010185558215611a8b579182015b82811115611a8a578235825591602001919060010190611a6f565b5b509050611a989190611b9c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611add57803560ff1916838001178555611b0b565b82800160010185558215611b0b579182015b82811115611b0a578235825591602001919060010190611aef565b5b509050611b189190611b9c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611b5d57805160ff1916838001178555611b8b565b82800160010185558215611b8b579182015b82811115611b8a578251825591602001919060010190611b6f565b5b509050611b989190611b9c565b5090565b611bbe91905b80821115611bba576000816000905550600101611ba2565b5090565b90565b600081359050611bd081612a45565b92915050565b600081519050611be581612a45565b92915050565b60008083601f840112611bfd57600080fd5b8235905067ffffffffffffffff811115611c1657600080fd5b602083019150836020820283011115611c2e57600080fd5b9250929050565b600081359050611c4481612a5c565b92915050565b600081359050611c5981612a73565b92915050565b600081359050611c6e81612a8a565b92915050565b60008083601f840112611c8657600080fd5b8235905067ffffffffffffffff811115611c9f57600080fd5b602083019150836001820283011115611cb757600080fd5b9250929050565b600082601f830112611ccf57600080fd5b8135611ce2611cdd82612827565b6127fa565b91508082526020830160208301858383011115611cfe57600080fd5b611d098382846129f2565b50505092915050565b600081359050611d2181612aa1565b92915050565b60008083601f840112611d3957600080fd5b8235905067ffffffffffffffff811115611d5257600080fd5b602083019150836001820283011115611d6a57600080fd5b9250929050565b600081359050611d8081612ab8565b92915050565b600060208284031215611d9857600080fd5b6000611da684828501611bd6565b91505092915050565b60008060208385031215611dc257600080fd5b600083013567ffffffffffffffff811115611ddc57600080fd5b611de885828601611beb565b92509250509250929050565b600060208284031215611e0657600080fd5b6000611e1484828501611c4a565b91505092915050565b60008060408385031215611e3057600080fd5b6000611e3e85828601611c4a565b9250506020611e4f85828601611bc1565b9150509250929050565b600080600060608486031215611e6e57600080fd5b6000611e7c86828701611c4a565b9350506020611e8d86828701611bc1565b9250506040611e9e86828701611bc1565b9150509250925092565b600080600060608486031215611ebd57600080fd5b6000611ecb86828701611c4a565b9350506020611edc86828701611bc1565b9250506040611eed86828701611c35565b9150509250925092565b600080600060608486031215611f0c57600080fd5b6000611f1a86828701611c4a565b9350506020611f2b86828701611c4a565b9250506040611f3c86828701611c4a565b9150509250925092565b60008060408385031215611f5957600080fd5b6000611f6785828601611c4a565b9250506020611f7885828601611c5f565b9150509250929050565b600080600060608486031215611f9757600080fd5b6000611fa586828701611c4a565b9350506020611fb686828701611c5f565b9250506040611fc786828701611bc1565b9150509250925092565b600080600060408486031215611fe657600080fd5b6000611ff486828701611c4a565b935050602084013567ffffffffffffffff81111561201157600080fd5b61201d86828701611c74565b92509250509250925092565b60008060006040848603121561203e57600080fd5b600061204c86828701611c4a565b935050602084013567ffffffffffffffff81111561206957600080fd5b61207586828701611d27565b92509250509250925092565b60008060008060006060868803121561209957600080fd5b60006120a788828901611c4a565b955050602086013567ffffffffffffffff8111156120c457600080fd5b6120d088828901611d27565b9450945050604086013567ffffffffffffffff8111156120ef57600080fd5b6120fb88828901611d27565b92509250509295509295909350565b6000806040838503121561211d57600080fd5b600061212b85828601611c4a565b925050602061213c85828601611d71565b9150509250929050565b6000806000806060858703121561215c57600080fd5b600061216a87828801611c4a565b945050602061217b87828801611d71565b935050604085013567ffffffffffffffff81111561219857600080fd5b6121a487828801611c74565b925092505092959194509250565b6000806000606084860312156121c757600080fd5b60006121d586828701611c4a565b93505060206121e686828701611d71565b925050604084013567ffffffffffffffff81111561220357600080fd5b61220f86828701611cbe565b9150509250925092565b60006020828403121561222b57600080fd5b600061223984828501611c5f565b91505092915050565b60006020828403121561225457600080fd5b600061226284828501611d12565b91505092915050565b6000612277838361240a565b905092915050565b61228881612998565b82525050565b61229781612908565b82525050565b6122a6816128f6565b82525050565b60006122b782612863565b6122c1818561289c565b9350836020820285016122d385612853565b8060005b8581101561230f57848403895281516122f0858261226b565b94506122fb8361288f565b925060208a019950506001810190506122d7565b50829750879550505050505092915050565b61232a8161291a565b82525050565b61233981612926565b82525050565b61234881612930565b82525050565b600061235a83856128be565b93506123678385846129f2565b61237083612a34565b840190509392505050565b600061238783856128cf565b93506123948385846129f2565b82840190509392505050565b60006123ab82612879565b6123b581856128be565b93506123c5818560208601612a01565b6123ce81612a34565b840191505092915050565b60006123e482612879565b6123ee81856128cf565b93506123fe818560208601612a01565b80840191505092915050565b60006124158261286e565b61241f81856128ad565b935061242f818560208601612a01565b61243881612a34565b840191505092915050565b61244c816129aa565b82525050565b600061245e83856128da565b935061246b8385846129f2565b61247483612a34565b840190509392505050565b600061248b83856128eb565b93506124988385846129f2565b82840190509392505050565b60006124af82612884565b6124b981856128da565b93506124c9818560208601612a01565b6124d281612a34565b840191505092915050565b60006124ea6024836128eb565b91507f696e74657266616365496d706c656d656e74657228627974657333322c62797460008301527f65733429000000000000000000000000000000000000000000000000000000006020830152602482019050919050565b6000612550602e836128da565b91507f436f6e747261637420696e7374616e63652068617320616c726561647920626560008301527f656e20696e697469616c697a65640000000000000000000000000000000000006020830152604082019050919050565b6125b28161298e565b82525050565b60006125c582848661237b565b91508190509392505050565b60006125dd82846123d9565b915081905092915050565b60006125f582848661247f565b91508190509392505050565b600061260c826124dd565b9150819050919050565b600060208201905061262b600083018461229d565b92915050565b6000602082019050612646600083018461227f565b92915050565b6000602082019050612661600083018461228e565b92915050565b6000602082019050818103600083015261268181846122ac565b905092915050565b600060208201905061269e6000830184612321565b92915050565b60006020820190506126b96000830184612330565b92915050565b60006040820190506126d46000830185612330565b6126e16020830184612330565b9392505050565b60006020820190506126fd600083018461233f565b92915050565b6000602082019050818103600083015261271e81848661234e565b90509392505050565b6000602082019050818103600083015261274181846123a0565b905092915050565b600060208201905061275e6000830184612443565b92915050565b6000602082019050818103600083015261277f818486612452565b90509392505050565b600060208201905081810360008301526127a281846124a4565b905092915050565b600060208201905081810360008301526127c381612543565b9050919050565b60006040820190506127df60008301856125a9565b81810360208301526127f181846123a0565b90509392505050565b6000604051905081810181811067ffffffffffffffff8211171561281d57600080fd5b8060405250919050565b600067ffffffffffffffff82111561283e57600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006129018261296e565b9050919050565b60006129138261296e565b9050919050565b60008115159050919050565b6000819050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000612967826128f6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006129a3826129ce565b9050919050565b60006129b5826129bc565b9050919050565b60006129c78261296e565b9050919050565b60006129d9826129e0565b9050919050565b60006129eb8261296e565b9050919050565b82818337600083830152505050565b60005b83811015612a1f578082015181840152602081019050612a04565b83811115612a2e576000848401525b50505050565b6000601f19601f8301169050919050565b612a4e816128f6565b8114612a5957600080fd5b50565b612a658161291a565b8114612a7057600080fd5b50565b612a7c81612926565b8114612a8757600080fd5b50565b612a9381612930565b8114612a9e57600080fd5b50565b612aaa8161295c565b8114612ab557600080fd5b50565b612ac18161298e565b8114612acc57600080fd5b5056fea365627a7a723158202fda2c024a2da4afe674afa87d76c348aaefe30595ce68286e1543f091b6791a6c6578706572696d656e74616cf564736f6c63430005100040","address":{"rskMainnet":"0x2D6EEdDDe13832512C68F9Ed7ccf44B728a2be70","rskTestnet":"0xe559e468C08f30518b4EE8bf7f9374736489C38b"}} diff --git a/src/types/enums.ts b/src/types/enums.ts index 4b5b086..57c5de0 100644 --- a/src/types/enums.ts +++ b/src/types/enums.ts @@ -7,7 +7,7 @@ export enum NetworkId { } /** - * Represents some of the chain ids listed in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) + * Represents some of the chain hexas listed in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) */ export enum ChainId { RSK = '0x80000089', @@ -16,6 +16,16 @@ export enum ChainId { LITECOIN = '0x80000002' } +/** + * Represents some of the chain index listed in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) + */ +export enum CoinType { + RSK = 137, + BITCOIN = 0, + ETHEREUM = 60, + LITECOIN = 2 +} + /** * Supported feedback languages */ diff --git a/src/types/resolutions.ts b/src/types/resolutions.ts index 7b776c8..9b67e83 100644 --- a/src/types/resolutions.ts +++ b/src/types/resolutions.ts @@ -20,7 +20,7 @@ export interface Resolutions { * Resolves the given domain using the AbstractMultiChainResolver interface * * @param domain - Domain to be resolved - * @param chainId - chain identifier listed in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) + * @param chainId - chain hexa or index listed in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) */ chainAddr(domain: string, chainId: ChainId): Promise; @@ -47,6 +47,21 @@ export interface Resolutions { domain: string, addr: string, chainId: ChainId, options?: TransactionOptions ): Promise; + /** + * Get decoded contenthash of a given domain. + * + * @param domain - Domain to be resolved + */ + contenthash(domain: string): Promise; + + /** + * Set contenthash of a given domain. + * + * @param domain - Domain to be resolved + * @param content - Content to be associated to the given domain. Must be decoded, the library will encode and save it. + */ + setContenthash(domain: string, content: string, options?: TransactionOptions): any; + /** * Set resolver of a given domain. * @@ -78,3 +93,9 @@ export interface Resolutions { */ name(address: string): Promise; } + +export interface DecodedContenthash { + protocolType: string; + + decoded: string; +} diff --git a/src/types/rns.ts b/src/types/rns.ts index 2831663..5e7fa78 100644 --- a/src/types/rns.ts +++ b/src/types/rns.ts @@ -5,6 +5,7 @@ import { ChainId } from './enums'; import { Utils } from './utils'; import { Subdomains } from './subdomains'; import { TransactionOptions } from './options'; +import { DecodedContenthash } from './resolutions'; /** * web3.eth.Contract wrapper. Contains an instance for each Contract used to run the lib. @@ -57,6 +58,22 @@ export default interface RNS { domain: string, addr: string, chainId?: ChainId, options?: TransactionOptions, ): Promise; + /** + * Get decoded contenthash of a given domain. + * + * @param domain - Domain to be resolved + */ + contenthash(domain: string): Promise; + + /** + * Set contenthash of a given domain. + * + * @param domain - Domain to be resolved + * @param content - Content to be associated to the given domain. Must be decoded, the library will encode and save it. + */ + setContenthash(domain: string, content: string, options?: TransactionOptions): any; + + /** * Set resolver of a given domain. * diff --git a/test/local/addr.test.ts b/test/local/addr.test.ts new file mode 100644 index 0000000..41c5cef --- /dev/null +++ b/test/local/addr.test.ts @@ -0,0 +1,113 @@ +import { + accounts, web3, defaultSender, +} from '@openzeppelin/test-environment'; +import { hash as namehash } from 'eth-ens-namehash'; +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import { NO_ADDR_RESOLUTION_SET, NO_RESOLVER, NO_ADDR_RESOLUTION } from '../../src/errors'; +import { asyncExpectThrowRNSError } from '../utils'; +import RNS from '../../src/index'; +import { labelhash } from '../../src/utils'; +import { + expectNoResolverError, deployDefinitiveResolver, deployRegistryAndCreateTldNode, + getRNSInstance, deployPublicResolver, deployNameResolver, deployMultichainResolver, +} from './helpers'; + +const web3Instance = web3 as unknown as Web3; +const rsk3Instance = new Rsk3(web3.currentProvider); + +describe.each([ + ['web3', web3Instance], + ['rsk3', rsk3Instance], +])('%s - addr resolution', (name, blockchainApiInstance) => { + const [resolution] = accounts; + + let registry: any; + let publicResolver: any; + let rns: RNS; + + describe('public and multichain resolver', () => { + beforeEach(async () => { + registry = await deployRegistryAndCreateTldNode(); + publicResolver = await deployPublicResolver(registry); + + await registry.setResolver(namehash('rsk'), publicResolver.address); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + it('should resolve a name with public resolver', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await publicResolver.setAddr(namehash('alice.rsk'), resolution); + + const addr = await rns.addr('alice.rsk'); + expect(addr).toBe(resolution); + }); + + it('should resolve an address with multichain resolver', async () => { + const multichainResolver = await deployMultichainResolver(registry, publicResolver); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await registry.setResolver(namehash('alice.rsk'), multichainResolver.address); + + await multichainResolver.setAddr(namehash('alice.rsk'), resolution); + + const actualAddr = await rns.addr('alice.rsk'); + expect(actualAddr).toBe(resolution); + }); + + it('should throw an error when resolver has not been set', async () => { + await expectNoResolverError(registry, () => rns.addr('noresolver.rsk')); + }); + + it('should throw an error when resolver does not support addr interface', async () => { + // resolver address is the NameResolver contract, an ERC165 that not supports addr interface + const nameResolver = await deployNameResolver(registry); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('anothererc165'), defaultSender); + await registry.setResolver(namehash('anothererc165.rsk'), nameResolver.address); + await asyncExpectThrowRNSError(() => rns.addr('anothererc165.rsk'), NO_ADDR_RESOLUTION); + }); + + it('should throw an error when no resolution set', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolution'), defaultSender); + + await asyncExpectThrowRNSError(() => rns.addr('noresolution.rsk'), NO_ADDR_RESOLUTION_SET); + }); + + it('should throw an error when domain do not exist', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noexists.rsk'), NO_RESOLVER); + }); + }); + + describe('definitive resolver', () => { + let proxy: any; + + beforeEach(async () => { + ({ proxy, registry } = await deployDefinitiveResolver()); + + const options = { + contractAddresses: { + registry: registry.address, + }, + }; + + rns = new RNS(blockchainApiInstance, options); + }); + + it('should resolve a name', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await proxy.methods['setAddr(bytes32,address)'](namehash('alice.rsk'), resolution.toLowerCase(), { from: defaultSender }); + + const addr = await rns.addr('alice.rsk'); + expect(addr).toBe(resolution); + }); + + it('should throw an error when no resolution set', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolution'), defaultSender); + + await asyncExpectThrowRNSError(() => rns.addr('noresolution.rsk'), NO_ADDR_RESOLUTION_SET); + }); + }); +}); diff --git a/test/local/rns.available.test.ts b/test/local/available.test.ts similarity index 89% rename from test/local/rns.available.test.ts rename to test/local/available.test.ts index 564642b..c39c5d6 100644 --- a/test/local/rns.available.test.ts +++ b/test/local/available.test.ts @@ -18,9 +18,9 @@ import { } from '../../src/errors'; import { asyncExpectThrowRNSError } from '../utils'; import RNS from '../../src/index'; -import { Options } from '../../src/types'; import { labelhash } from '../../src/utils'; import { ZERO_ADDRESS } from '../../src/constants'; +import { deployRegistryAndCreateTldNode, getRNSInstance } from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -29,27 +29,14 @@ describe.each([ ['web3', web3Instance], ['rsk3', rsk3Instance], ])('%s - subdomains.available', (apiName, blockchainApiInstance) => { - const TLD = 'rsk'; - let registry: any; let rns: RNS; - let options: Options; describe('validations', () => { beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - - registry = await Registry.new(); + registry = await deployRegistryAndCreateTldNode(); - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); - - options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); + rns = getRNSInstance(blockchainApiInstance, registry); }); it('should return false when sending a subdomain', async () => { @@ -90,7 +77,7 @@ describe.each([ }); it('should fail when tld node does not have owner', async () => { - await registry.setOwner(namehash(TLD), ZERO_ADDRESS); + await registry.setOwner(namehash('rsk'), ZERO_ADDRESS); await asyncExpectThrowRNSError(() => rns.available('domain.rsk'), NO_TLD_OWNER); }); }); @@ -137,13 +124,13 @@ describe.each([ await rif.transfer(defaultSender, web3.utils.toBN('50000000000000000000000')); // token registrar - const tokenRegistrar = await TokenRegistrar.new(registry.address, namehash(TLD), rif.address); + const tokenRegistrar = await TokenRegistrar.new(registry.address, namehash('rsk'), rif.address); // rskOwner deployment - const rskOwner = await RSKOwner.new(tokenRegistrar.address, registry.address, namehash(TLD)); + const rskOwner = await RSKOwner.new(tokenRegistrar.address, registry.address, namehash('rsk')); // give rsk ownership to rskOwner - await registry.setSubnodeOwner('0x00', labelhash(TLD), rskOwner.address); + await registry.setSubnodeOwner('0x00', labelhash('rsk'), rskOwner.address); const bytesUtils = await BytesUtils.new(); @@ -161,13 +148,7 @@ describe.each([ await rskOwner.addRegistrar(fifsRegistrar.address); - options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); + rns = getRNSInstance(blockchainApiInstance, registry); }); it('should return an empty array just rsk', async () => { diff --git a/test/local/chainAddr.test.ts b/test/local/chainAddr.test.ts new file mode 100644 index 0000000..fb7b9b9 --- /dev/null +++ b/test/local/chainAddr.test.ts @@ -0,0 +1,120 @@ +import { web3, defaultSender } from '@openzeppelin/test-environment'; +import { hash as namehash } from 'eth-ens-namehash'; +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import { formatsByCoinType } from '@ensdomains/address-encoder'; +import { NO_CHAIN_ADDR_RESOLUTION_SET, NO_RESOLVER, NO_CHAIN_ADDR_RESOLUTION } from '../../src/errors'; +import { asyncExpectThrowRNSError } from '../utils'; +import RNS from '../../src/index'; +import { ChainId } from '../../src/types'; +import { labelhash, toChecksumAddress } from '../../src/utils'; +import { + expectNoResolverError, deployDefinitiveResolver, deployRegistryAndCreateTldNode, + getRNSInstance, deployPublicResolver, deployMultichainResolver, deployNameResolver, +} from './helpers'; +import { CoinType } from '../../src/types/enums'; + +const web3Instance = web3 as unknown as Web3; +const rsk3Instance = new Rsk3(web3.currentProvider); + +describe.each([ + ['web3', web3Instance], + ['rsk3', rsk3Instance], +])('%s - chainAddr resolution', (name, blockchainApiInstance) => { + let registry: any; + let multichainResolver: any; + let rns: RNS; + + describe('public and multichain resolver', () => { + beforeEach(async () => { + registry = await deployRegistryAndCreateTldNode(); + + const publicResolver = await deployPublicResolver(registry); + multichainResolver = await deployMultichainResolver(registry, publicResolver); + + await registry.setResolver(namehash('rsk'), multichainResolver.address); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + it('should resolve a name for BTC', async () => { + const btcAddress = '1Ftu4C8VW18RkB8PZxXwwHocMLyEynLcrG'; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await multichainResolver.setChainAddr(namehash('alice.rsk'), ChainId.BITCOIN, btcAddress); + + const addr = await rns.addr('alice.rsk', ChainId.BITCOIN); + expect(addr).toBe(btcAddress); + }); + + it('should resolve a name for ETH', async () => { + const ethAddress = '0x0000000000000000000000000000000000000001'; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await multichainResolver.setChainAddr(namehash('alice.rsk'), ChainId.ETHEREUM, ethAddress); + + const addr = await rns.addr('alice.rsk', ChainId.ETHEREUM); + expect(addr).toBe(toChecksumAddress(ethAddress)); + }); + + it('should throw an error when resolver has not been set', async () => { + await expectNoResolverError(registry, () => rns.addr('noresolver.rsk', ChainId.BITCOIN)); + }); + + it('should throw an error when resolver does not support chainAddr interface', async () => { + // the address is the NameResolver contract, an ERC165 that not supports chainAddr interface + const nameResolver = await deployNameResolver(registry); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('anothererc165'), defaultSender); + await registry.setResolver(namehash('anothererc165.rsk'), nameResolver.address); + await asyncExpectThrowRNSError(() => rns.addr('anothererc165.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION); + }); + + it('should throw an error when no resolution set', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolution'), defaultSender); + + await asyncExpectThrowRNSError(() => rns.addr('noresolution.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION_SET); + }); + + it('should throw an error when domain do not exist', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noexists.rsk', ChainId.BITCOIN), NO_RESOLVER); + }); + }); + + describe('definitive resolver', () => { + let proxy: any; + beforeEach(async () => { + ({ proxy, registry } = await deployDefinitiveResolver()); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + it('should resolve a name for BTC', async () => { + const btcAddress = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'; + const decoded = formatsByCoinType[CoinType.BITCOIN].decoder(btcAddress); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await proxy.methods['setAddr(bytes32,uint256,bytes)'](namehash('alice.rsk'), CoinType.BITCOIN, decoded, { from: defaultSender }); + + const addr = await rns.addr('alice.rsk', ChainId.BITCOIN); + expect(addr).toBe(btcAddress); + }); + + it('should resolve a name for ETH', async () => { + const ethAddress = '0x0000000000000000000000000000000000000001'; + const decoded = formatsByCoinType[CoinType.ETHEREUM].decoder(ethAddress); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await proxy.methods['setAddr(bytes32,uint256,bytes)'](namehash('alice.rsk'), CoinType.ETHEREUM, decoded, { from: defaultSender }); + + const addr = await rns.addr('alice.rsk', ChainId.ETHEREUM); + expect(addr).toBe(ethAddress); + }); + + it('should throw an error when no resolution set', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolution'), defaultSender); + + await asyncExpectThrowRNSError(() => rns.addr('noresolution.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION_SET); + }); + }); +}); diff --git a/test/local/contenthash.test.ts b/test/local/contenthash.test.ts new file mode 100644 index 0000000..bff2a9e --- /dev/null +++ b/test/local/contenthash.test.ts @@ -0,0 +1,95 @@ + +import { + web3, defaultSender, +} from '@openzeppelin/test-environment'; +import { hash as namehash } from 'eth-ens-namehash'; +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import { + UNSUPPORTED_CONTENTHASH_PROTOCOL, NO_CONTENTHASH_INTERFACE, NO_CONTENTHASH_SET, +} from '../../src/errors'; +import { asyncExpectThrowRNSError } from '../utils'; +import RNS from '../../src/index'; +import { labelhash } from '../../src/utils'; +import { + deployDefinitiveResolver, expectNoResolverError, getRNSInstance, deployNameResolver, +} from './helpers'; +import ContenthashHelper from '../../src/contenthash-helper'; + +const web3Instance = web3 as unknown as Web3; +const rsk3Instance = new Rsk3(web3.currentProvider); + +describe.each([ + ['web3', web3Instance], + ['rsk3', rsk3Instance], +])('%s - contenthash resolution', (name, blockchainApiInstance) => { + let registry: any; + let rns: RNS; + let proxy: any; + const contenthashHelper = new ContenthashHelper(); + + beforeEach(async () => { + ({ proxy, registry } = await deployDefinitiveResolver()); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + const shouldDecodeProperly = async (expectedProtocol: string, expectedContent: string) => { + const encoded = contenthashHelper.encodeContenthash(`${expectedProtocol}://${expectedContent}`); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await proxy.methods['setContenthash(bytes32,bytes)'](namehash('alice.rsk'), encoded, { from: defaultSender }); + + const contenthash = await rns.contenthash('alice.rsk'); + expect(contenthash.protocolType).toBe(expectedProtocol); + expect(contenthash.decoded).toBe(expectedContent); + }; + + it('should get ipfs contenthash', async () => { + const hash = 'QmRAQB6YaCyidP37UdDnjFY5vQuiBrcqdyoW1CuDgwxkD4'; + await shouldDecodeProperly('ipfs', hash); + }); + + it('should get bzz contenthash', async () => { + const hash = 'd1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162'; + await shouldDecodeProperly('bzz', hash); + }); + + it('should get onion contenthash', async () => { + const hash = 'zqktlwi4fecvo6ri'; + await shouldDecodeProperly('onion', hash); + }); + + it('should get onion3 contenthash', async () => { + const hash = 'p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd'; + await shouldDecodeProperly('onion3', hash); + }); + + it('should fail if invalid contenthash', async () => { + const encoded = '0x000000123456789abcdef'; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await proxy.methods['setContenthash(bytes32,bytes)'](namehash('alice.rsk'), encoded, { from: defaultSender }); + + await asyncExpectThrowRNSError(() => rns.contenthash('alice.rsk'), UNSUPPORTED_CONTENTHASH_PROTOCOL); + }); + + it('should fail if no contenthash set', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await asyncExpectThrowRNSError(() => rns.contenthash('alice.rsk'), NO_CONTENTHASH_SET); + }); + + it('should throw an error when resolver does not support contenthash interface', async () => { + // the address is the NameResolver contract, an ERC165 that not supports chainAddr interface + const nameResolver = await deployNameResolver(registry); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('anothererc165'), defaultSender); + await registry.setResolver(namehash('anothererc165.rsk'), nameResolver.address); + await asyncExpectThrowRNSError(() => rns.contenthash('anothererc165.rsk'), NO_CONTENTHASH_INTERFACE); + }); + + it('should throw an error when resolver has not been set', async () => { + await expectNoResolverError(registry, () => rns.contenthash('noresolver.rsk')); + }); +}); diff --git a/test/local/rns.error.test.ts b/test/local/error.test.ts similarity index 100% rename from test/local/rns.error.test.ts rename to test/local/error.test.ts diff --git a/test/local/helpers.ts b/test/local/helpers.ts new file mode 100644 index 0000000..38740fa --- /dev/null +++ b/test/local/helpers.ts @@ -0,0 +1,97 @@ +import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; +import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; +import NameResolverData from '@rsksmart/rns-reverse/NameResolverData.json'; +import ReverseRegistrarData from '@rsksmart/rns-reverse/ReverseRegistrarData.json'; +import ChainAddrResolverData from '@rsksmart/rns-resolver/ChainAddrResolverData.json'; +import { + contract, defaultSender, +} from '@openzeppelin/test-environment'; +import { encodeCall } from '@openzeppelin/upgrades'; +import ResolverV1Data from '../../src/resolvers/ResolverV1Data.json'; +import ProxyAdminData from '../../src/resolvers/ProxyAdminData.json'; +import ProxyFactoryData from '../../src/resolvers/ProxyFactoryData.json'; +import { labelhash, namehash } from '../../src/utils'; +import { asyncExpectThrowRNSError } from '../utils'; +import { ZERO_ADDRESS } from '../../src/constants'; +import { NO_RESOLVER } from '../../src/errors'; +import RNS from '../../src/index'; + +export const deployRegistryAndCreateTldNode = async (): Promise => { + const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); + + const registry = await Registry.new(); + + await registry.setSubnodeOwner('0x00', labelhash('rsk'), defaultSender); + + return registry; +}; + +export const deployPublicResolver = async (registry: any): Promise => { + const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); + return PublicResolver.new(registry.address); +}; + +export const deployNameResolver = async (registry: any): Promise => { + const NameResolver = contract.fromABI(NameResolverData.abi, NameResolverData.bytecode); + return NameResolver.new(registry.address); +}; + +export const deployMultichainResolver = async ( + registry: any, publicResolver: any, +): Promise => { + const MultichainResolver = contract.fromABI( + ChainAddrResolverData.abi, ChainAddrResolverData.bytecode, + ); + + return MultichainResolver.new(registry.address, publicResolver.address); +}; + +export const deployReverseRegistrar = (registry: any): Promise => { + const ReverseRegistrar = contract.fromABI( + ReverseRegistrarData.abi, + ReverseRegistrarData.bytecode, + ); + + return ReverseRegistrar.new(registry.address); +}; +export const deployDefinitiveResolver = async (): Promise<{ + proxy: any, registry: any +}> => { + const ResolverV1 = contract.fromABI(ResolverV1Data.abi, ResolverV1Data.bytecode); + const ProxyFactory = contract.fromABI(ProxyFactoryData.abi, ProxyFactoryData.bytecode); + const ProxyAdmin = contract.fromABI(ProxyAdminData.abi, ProxyAdminData.bytecode); + + const proxyFactory = await ProxyFactory.new(); + const proxyAdmin = await ProxyAdmin.new(); + const resolverV1 = await ResolverV1.new(); + + const registry = await deployRegistryAndCreateTldNode(); + const salt = '16'; + const data = encodeCall('initialize', ['address'], [registry.address]); + await proxyFactory.deploy(salt, resolverV1.address, proxyAdmin.address, data); + + const resolverAddress = await proxyFactory.getDeploymentAddress(salt, defaultSender); + + const proxy = contract.fromABI(ResolverV1Data.abi, ResolverV1Data.bytecode, resolverAddress); + + await registry.setResolver(namehash('rsk'), resolverAddress); + + return { registry, proxy }; +}; + +export const expectNoResolverError = async (registry: any, fn: () => any) => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolver'), defaultSender); + await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); + + await asyncExpectThrowRNSError(fn, NO_RESOLVER); +}; + +export const getRNSInstance = (blockchainApiInstance: any, registry: any) => { + const options = { + contractAddresses: { + registry: registry.address, + }, + }; + + return new RNS(blockchainApiInstance, options); +}; diff --git a/test/local/rns.i18n.test.ts b/test/local/i18n.test.ts similarity index 60% rename from test/local/rns.i18n.test.ts rename to test/local/i18n.test.ts index bc24ee5..e3377ab 100644 --- a/test/local/rns.i18n.test.ts +++ b/test/local/i18n.test.ts @@ -1,8 +1,4 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; -import { - contract, web3, defaultSender, -} from '@openzeppelin/test-environment'; +import { web3, defaultSender } from '@openzeppelin/test-environment'; import { hash as namehash } from 'eth-ens-namehash'; import Web3 from 'web3'; import Rsk3 from '@rsksmart/rsk3'; @@ -13,6 +9,7 @@ import RNS from '../../src/index'; import { labelhash } from '../../src/utils'; import { Lang } from '../../src/types/enums'; import { Options } from '../../src/types'; +import { deployRegistryAndCreateTldNode } from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -30,21 +27,10 @@ describe.each([ [Lang.ru], [Lang.zh], ])('- lang %s', (lang) => { - const TLD = 'rsk'; - - let registry: any; - let publicResolver: any; let options: Options; beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); - registry = await Registry.new(); - publicResolver = await PublicResolver.new(registry.address); - - await registry.setDefaultResolver(publicResolver.address); - - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); + const registry = await deployRegistryAndCreateTldNode(); options = { contractAddresses: { @@ -53,7 +39,7 @@ describe.each([ lang, }; - await registry.setSubnodeOwner(namehash(TLD), labelhash('noresolver'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolver'), defaultSender); await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); }); diff --git a/test/local/rns.resolve.reverse.test.ts b/test/local/reverse.test.ts similarity index 56% rename from test/local/rns.resolve.reverse.test.ts rename to test/local/reverse.test.ts index 6f5ee78..def4277 100644 --- a/test/local/rns.resolve.reverse.test.ts +++ b/test/local/reverse.test.ts @@ -1,18 +1,15 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import NameResolverData from '@rsksmart/rns-reverse/NameResolverData.json'; -import ReverseRegistrarData from '@rsksmart/rns-reverse/ReverseRegistrarData.json'; -import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; -import { - contract, web3, defaultSender, accounts, -} from '@openzeppelin/test-environment'; +import { web3, defaultSender, accounts } from '@openzeppelin/test-environment'; import { hash as namehash } from 'eth-ens-namehash'; import Web3 from 'web3'; import Rsk3 from '@rsksmart/rsk3'; import { NO_REVERSE_RESOLUTION_SET, NO_NAME_RESOLUTION } from '../../src/errors'; import { asyncExpectThrowRNSError } from '../utils'; import RNS from '../../src/index'; -import { Options } from '../../src/types'; import { labelhash } from '../../src/utils'; +import { + deployRegistryAndCreateTldNode, getRNSInstance, deployNameResolver, + deployReverseRegistrar, deployPublicResolver, +} from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -25,31 +22,17 @@ describe.each([ let nameResolver: any; let reverseRegistrar: any; let rns: RNS; - let options: Options; beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const NameResolver = contract.fromABI(NameResolverData.abi, NameResolverData.bytecode); - const ReverseRegistrar = contract.fromABI( - ReverseRegistrarData.abi, - ReverseRegistrarData.bytecode, - ); - - registry = await Registry.new(); - nameResolver = await NameResolver.new(registry.address); - reverseRegistrar = await ReverseRegistrar.new(registry.address); + registry = await deployRegistryAndCreateTldNode(); + nameResolver = await deployNameResolver(registry); + reverseRegistrar = await deployReverseRegistrar(registry); await registry.setSubnodeOwner('0x00', labelhash('reverse'), defaultSender); await registry.setResolver(namehash('reverse'), nameResolver.address); await registry.setSubnodeOwner(namehash('reverse'), labelhash('addr'), reverseRegistrar.address); - options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); + rns = getRNSInstance(blockchainApiInstance, registry); }); it('should resolve an address', async () => { @@ -61,17 +44,9 @@ describe.each([ expect(actual).toBe(expected); }); - it('should throw an error when invalid ERC165 contract (account address) as reverse resolver', async () => { - const [alice, accountAsResolver] = accounts; - - await reverseRegistrar.claimWithResolver(alice, accountAsResolver, { from: alice }); - await asyncExpectThrowRNSError(() => rns.reverse(alice), NO_NAME_RESOLUTION); - }); - it('should throw an error when ERC165 that not support name interface (public resolver) as reverse resolver', async () => { const [alice] = accounts; - const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); - const publicResolver = await PublicResolver.new(registry.address); + const publicResolver = await deployPublicResolver(registry); await reverseRegistrar.claimWithResolver(alice, publicResolver.address, { from: alice }); await asyncExpectThrowRNSError(() => rns.reverse(alice), NO_NAME_RESOLUTION); diff --git a/test/local/rns.resolve.addr.test.ts b/test/local/rns.resolve.addr.test.ts deleted file mode 100644 index 1389ed5..0000000 --- a/test/local/rns.resolve.addr.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; -import NameResolverData from '@rsksmart/rns-reverse/NameResolverData.json'; -import { - accounts, contract, web3, defaultSender, -} from '@openzeppelin/test-environment'; -import { hash as namehash } from 'eth-ens-namehash'; -import Web3 from 'web3'; -import Rsk3 from '@rsksmart/rsk3'; -import { NO_ADDR_RESOLUTION_SET, NO_RESOLVER, NO_ADDR_RESOLUTION } from '../../src/errors'; -import { ZERO_ADDRESS } from '../../src/constants'; -import { asyncExpectThrowRNSError } from '../utils'; -import RNS from '../../src/index'; -import { Options } from '../../src/types'; -import { labelhash } from '../../src/utils'; - -const web3Instance = web3 as unknown as Web3; -const rsk3Instance = new Rsk3(web3.currentProvider); - -describe.each([ - ['web3', web3Instance], - ['rsk3', rsk3Instance], -])('%s - addr resolution', (name, blockchainApiInstance) => { - const [resolution, anotherAccount] = accounts; - - const TLD = 'rsk'; - - let registry: any; - let publicResolver: any; - let rns: RNS; - let options: Options; - - beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); - registry = await Registry.new(); - publicResolver = await PublicResolver.new(registry.address); - - await registry.setDefaultResolver(publicResolver.address); - - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); - - options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); - }); - - it('should resolve a name', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - await publicResolver.setAddr(namehash('alice.rsk'), resolution); - - const addr = await rns.addr('alice.rsk'); - expect(addr).toBe(resolution); - }); - - it('should throw an error when resolver has not been set', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('noresolver'), defaultSender); - await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); - - await asyncExpectThrowRNSError(() => rns.addr('noresolver.rsk'), NO_RESOLVER); - }); - - describe('should throw an error when resolver does not support addr interface', () => { - it('ERC165 contract as resolver that not implements addr method', async () => { - // resolver address is the NameResolver contract, an ERC165 that not supports addr interface - const NameResolver = contract.fromABI(NameResolverData.abi, NameResolverData.bytecode); - const nameResolver = await NameResolver.new(registry.address); - - await registry.setSubnodeOwner(namehash(TLD), labelhash('anothererc165'), defaultSender); - await registry.setResolver(namehash('anothererc165.rsk'), nameResolver.address); - await asyncExpectThrowRNSError(() => rns.addr('anothererc165.rsk'), NO_ADDR_RESOLUTION); - }); - - it('account address as a resolver', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('accountasresolver'), defaultSender); - await registry.setResolver(namehash('accountasresolver.rsk'), anotherAccount); - - await asyncExpectThrowRNSError(() => rns.addr('accountasresolver.rsk'), NO_ADDR_RESOLUTION); - }); - }); - - it('should throw an error when no resolution set', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('noresolution'), defaultSender); - - await asyncExpectThrowRNSError(() => rns.addr('noresolution.rsk'), NO_ADDR_RESOLUTION_SET); - }); - - it('should throw an error when domain do not exist', async () => { - await asyncExpectThrowRNSError(() => rns.addr('noexists.rsk'), NO_RESOLVER); - }); -}); diff --git a/test/local/rns.resolve.chainAddr.test.ts b/test/local/rns.resolve.chainAddr.test.ts deleted file mode 100644 index 4fceda3..0000000 --- a/test/local/rns.resolve.chainAddr.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; -import ChainAddrResolverData from '@rsksmart/rns-resolver/ChainAddrResolverData.json'; -import NameResolverData from '@rsksmart/rns-reverse/NameResolverData.json'; -import { - accounts, contract, web3, defaultSender, -} from '@openzeppelin/test-environment'; -import { hash as namehash } from 'eth-ens-namehash'; -import Web3 from 'web3'; -import Rsk3 from '@rsksmart/rsk3'; -import { NO_CHAIN_ADDR_RESOLUTION_SET, NO_RESOLVER, NO_CHAIN_ADDR_RESOLUTION } from '../../src/errors'; -import { ZERO_ADDRESS } from '../../src/constants'; -import { asyncExpectThrowRNSError } from '../utils'; -import RNS from '../../src/index'; -import { Options, ChainId } from '../../src/types'; -import { labelhash, toChecksumAddress } from '../../src/utils'; - -const web3Instance = web3 as unknown as Web3; -const rsk3Instance = new Rsk3(web3.currentProvider); - -describe.each([ - ['web3', web3Instance], - ['rsk3', rsk3Instance], -])('%s - chainAddr resolution', (name, blockchainApiInstance) => { - const [anotherAccount] = accounts; - - const TLD = 'rsk'; - - let registry: any; - let multichainResolver: any; - let rns: RNS; - let options: Options; - - beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); - const MultichainResolver = contract.fromABI( - ChainAddrResolverData.abi, ChainAddrResolverData.bytecode, - ); - - registry = await Registry.new(); - const publicResolver = await PublicResolver.new(registry.address); - multichainResolver = await MultichainResolver.new(registry.address, publicResolver.address); - - await registry.setDefaultResolver(multichainResolver.address); - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); - - options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); - }); - - it('should resolve a name for BTC', async () => { - const btcAddress = '1Ftu4C8VW18RkB8PZxXwwHocMLyEynLcrG'; - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - await multichainResolver.setChainAddr(namehash('alice.rsk'), ChainId.BITCOIN, btcAddress); - - const addr = await rns.addr('alice.rsk', ChainId.BITCOIN); - expect(addr).toBe(btcAddress); - }); - - it('should resolve a name for ETH', async () => { - const ethAddress = '0x0000000000000000000000000000000000000001'; - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - await multichainResolver.setChainAddr(namehash('alice.rsk'), ChainId.ETHEREUM, ethAddress); - - const addr = await rns.addr('alice.rsk', ChainId.ETHEREUM); - expect(addr).toBe(toChecksumAddress(ethAddress)); - }); - - it('should throw an error when resolver has not been set', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('noresolver'), defaultSender); - await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); - - await asyncExpectThrowRNSError(() => rns.addr('noresolver.rsk', ChainId.BITCOIN), NO_RESOLVER); - }); - - describe('should throw an error when resolver does not support chainAddr interface', () => { - it('ERC165 contract as resolver that not implements addr method', async () => { - // the address is the NameResolver contract, an ERC165 that not supports chainAddr interface - const NameResolver = contract.fromABI(NameResolverData.abi, NameResolverData.bytecode); - const nameResolver = await NameResolver.new(registry.address); - - await registry.setSubnodeOwner(namehash(TLD), labelhash('anothererc165'), defaultSender); - await registry.setResolver(namehash('anothererc165.rsk'), nameResolver.address); - await asyncExpectThrowRNSError(() => rns.addr('anothererc165.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION); - }); - - it('account address as a resolver', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('accountasresolver'), defaultSender); - await registry.setResolver(namehash('accountasresolver.rsk'), anotherAccount); - - await asyncExpectThrowRNSError(() => rns.addr('accountasresolver.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION); - }); - }); - - it('should throw an error when no resolution set', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('noresolution'), defaultSender); - - await asyncExpectThrowRNSError(() => rns.addr('noresolution.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION_SET); - }); - - it('should throw an error when domain do not exist', async () => { - await asyncExpectThrowRNSError(() => rns.addr('noexists.rsk', ChainId.BITCOIN), NO_RESOLVER); - }); -}); diff --git a/test/local/rns.resolve.setAddr.test.ts b/test/local/rns.resolve.setAddr.test.ts deleted file mode 100644 index 95ab48f..0000000 --- a/test/local/rns.resolve.setAddr.test.ts +++ /dev/null @@ -1,197 +0,0 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; -import NameResolverData from '@rsksmart/rns-reverse/NameResolverData.json'; -import ChainAddrResolverData from '@rsksmart/rns-resolver/ChainAddrResolverData.json'; -import { - contract, web3, defaultSender, accounts, -} from '@openzeppelin/test-environment'; -import { hash as namehash } from 'eth-ens-namehash'; -import Web3 from 'web3'; -import Rsk3 from '@rsksmart/rsk3'; -import { - NO_RESOLVER, INVALID_ADDRESS, NO_SET_ADDR, INVALID_CHECKSUM_ADDRESS, NO_ACCOUNTS_TO_SIGN, -} from '../../src/errors'; -import { ZERO_ADDRESS } from '../../src/constants'; -import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; -import RNS from '../../src/index'; -import { labelhash } from '../../src/utils'; - -const web3Instance = web3 as unknown as Web3; -const rsk3Instance = new Rsk3(web3.currentProvider); - -describe.each([ - ['web3', web3Instance], - ['rsk3', rsk3Instance], -])('%s - setAddr', (name, blockchainApiInstance) => { - const TLD = 'rsk'; - const addr = '0x0000000000000000000000000000000001000006'; - - let registry: any; - let publicResolver: any; - let rns: RNS; - - beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); - registry = await Registry.new(); - publicResolver = await PublicResolver.new(registry.address); - - await registry.setDefaultResolver(publicResolver.address); - - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); - - const options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); - }); - - it('should set an address if implements the multichain resolver', async () => { - const MultichainResolver = contract.fromABI( - ChainAddrResolverData.abi, ChainAddrResolverData.bytecode, - ); - - const multichainResolver = await MultichainResolver.new( - registry.address, publicResolver.address, - ); - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - await registry.setResolver(namehash('alice.rsk'), multichainResolver.address); - - await rns.setAddr('alice.rsk', addr); - - const actualAddr = await rns.addr('alice.rsk'); - expect(actualAddr).toBe(addr); - }); - - it('should set an address with public resolver', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - await rns.setAddr('alice.rsk', addr); - - const actualAddr = await rns.addr('alice.rsk'); - expect(actualAddr).toBe(addr); - }); - - it('should return a tx receipt when setting an address', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - const tx = await rns.setAddr('alice.rsk', addr); - - expect(tx.transactionHash).toBeTruthy(); - }); - - it('should set an address when the library is instantiated with a different networkId', async () => { - const options = { - contractAddresses: { - registry: registry.address, - }, - networkId: 18, - }; - - rns = new RNS(blockchainApiInstance, options); - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - await rns.setAddr('alice.rsk', addr); - - const actualAddr = await rns.addr('alice.rsk'); - expect(actualAddr).toBe(addr); - }); - - it('should throw an error when address is invalid', async () => { - await asyncExpectThrowRNSError(() => rns.setAddr('alice.rsk', 'invalidaddress'), INVALID_ADDRESS); - }); - - it('should throw an error when address has invalid checksum', async () => { - await asyncExpectThrowRNSError(() => rns.setAddr('alice.rsk', '0x0000000000000000000000000000000001ABcdEF'), INVALID_CHECKSUM_ADDRESS); - }); - - it('should throw an error when resolver has not been set', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('noresolver'), defaultSender); - await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); - - await asyncExpectThrowRNSError(() => rns.setAddr('noresolver.rsk', addr), NO_RESOLVER); - }); - - describe('should throw an error when resolver does not support setAddr interface', () => { - it('ERC165 contract as resolver that not implements addr method', async () => { - // resolver address is the NameResolver contract, an ERC165 that not supports addr interface - const NameResolver = contract.fromABI(NameResolverData.abi, NameResolverData.bytecode); - const nameResolver = await NameResolver.new(registry.address); - - await registry.setSubnodeOwner(namehash(TLD), labelhash('anothererc165'), defaultSender); - await registry.setResolver(namehash('anothererc165.rsk'), nameResolver.address); - - await asyncExpectThrowRNSError(() => rns.setAddr('anothererc165.rsk', addr), NO_SET_ADDR); - }); - - it('account address as a resolver', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('accountasresolver'), defaultSender); - await registry.setResolver(namehash('accountasresolver.rsk'), defaultSender); - - await asyncExpectThrowRNSError(() => rns.setAddr('accountasresolver.rsk', addr), NO_SET_ADDR); - }); - }); - - it('should throw an error when domain do not exist', async () => { - await asyncExpectThrowRNSError(() => rns.setAddr('noexists.rsk', addr), NO_RESOLVER); - }); - - describe('custom tx options', () => { - it('should send custom gasPrice', async () => { - const gasPrice = '70000000'; - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { gasPrice }); - - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); - - expect(tx.gasPrice).toEqual(gasPrice.toString()); - }); - - it('should send custom gas', async () => { - const gas = 80000; - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { gas }); - - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); - - expect(tx.gas).toEqual(gas); - expect(tx.from).toEqual(defaultSender); - }); - - it('should send custom sender', async () => { - const [from] = accounts; - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), from); - - const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { from }); - - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); - - expect(tx.from).toEqual(from); - }); - }); -}); - -describe.each([ - ['web3 mainnet', new Web3(PUBLIC_NODE_MAINNET)], - ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], - ['rsk mainnet', new Rsk3(PUBLIC_NODE_MAINNET)], - ['rsk testnet', new Rsk3(PUBLIC_NODE_TESTNET)], -])('%s - public nodes setAddr', (name, blockchainApiInstance) => { - test('should fail when blockchain api instance does not contain accounts to sing the tx', async () => { - const rns = new RNS(blockchainApiInstance); - await asyncExpectThrowRNSError( - () => rns.setAddr('testing.rsk', '0x0000000000000000000000000000000000000001'), - NO_ACCOUNTS_TO_SIGN, - ); - }); -}); diff --git a/test/local/rns.resolve.setChainAddr.test.ts b/test/local/rns.resolve.setChainAddr.test.ts deleted file mode 100644 index 719a5da..0000000 --- a/test/local/rns.resolve.setChainAddr.test.ts +++ /dev/null @@ -1,190 +0,0 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; -import ChainAddrResolverData from '@rsksmart/rns-resolver/ChainAddrResolverData.json'; -import NameResolverData from '@rsksmart/rns-reverse/NameResolverData.json'; -import { - contract, web3, defaultSender, accounts, -} from '@openzeppelin/test-environment'; -import { hash as namehash } from 'eth-ens-namehash'; -import Web3 from 'web3'; -import Rsk3 from '@rsksmart/rsk3'; -import { - NO_RESOLVER, NO_SET_CHAIN_ADDR, NO_ACCOUNTS_TO_SIGN, INVALID_CHECKSUM_ADDRESS, -} from '../../src/errors'; -import { ZERO_ADDRESS } from '../../src/constants'; -import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; -import RNS from '../../src/index'; -import { ChainId } from '../../src/types'; -import { labelhash } from '../../src/utils'; - -const web3Instance = web3 as unknown as Web3; -const rsk3Instance = new Rsk3(web3.currentProvider); - -describe.each([ - ['web3', web3Instance], - ['rsk3', rsk3Instance], -])('%s - setChainAddr', (name, blockchainApiInstance) => { - const TLD = 'rsk'; - const rskAddr = '0x0000000000000000000000000000000001000006'; - const ethAddr = '0x0000000000000000000000000000000012345678'; - const btcAddr = '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2'; - - let registry: any; - let multichainResolver: any; - let rns: RNS; - - beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); - const MultichainResolver = contract.fromABI( - ChainAddrResolverData.abi, ChainAddrResolverData.bytecode, - ); - - registry = await Registry.new(); - const publicResolver = await PublicResolver.new(registry.address); - multichainResolver = await MultichainResolver.new(registry.address, publicResolver.address); - - await registry.setDefaultResolver(multichainResolver.address); - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); - - const options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); - }); - - it('should set an address for RSK', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - await rns.setAddr('alice.rsk', rskAddr, ChainId.RSK); - - const actualAddr = await rns.addr('alice.rsk', ChainId.RSK); - expect(actualAddr).toBe(rskAddr); - }); - - it('should set an address for ETH', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM); - - const actualAddr = await rns.addr('alice.rsk', ChainId.ETHEREUM); - expect(actualAddr).toBe(ethAddr); - }); - - it('should set an address for BTC', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - await rns.setAddr('alice.rsk', btcAddr, ChainId.BITCOIN); - - const actualAddr = await rns.addr('alice.rsk', ChainId.BITCOIN); - expect(actualAddr).toBe(btcAddr); - }); - - it('should return a tx receipt when setting an address', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - const tx = await rns.setAddr('alice.rsk', rskAddr, ChainId.RSK); - - expect(tx.transactionHash).toBeTruthy(); - }); - - it('should throw an error when invalid checksum for RSK', async () => { - const address = '0x53BF4d5cF81F8c52644912cfae4d0E3EA7faDd5B'; // valid for ethereum - - await asyncExpectThrowRNSError(() => rns.setAddr('alice.rsk', address, ChainId.RSK), INVALID_CHECKSUM_ADDRESS); - }); - - it('should throw an error when invalid checksum for Ethereum', async () => { - const address = '0x53Bf4d5cF81F8c52644912cfaE4d0E3EA7FAdD5b'; // valid for rsk mainnet - - await asyncExpectThrowRNSError(() => rns.setAddr('alice.rsk', address, ChainId.ETHEREUM), INVALID_CHECKSUM_ADDRESS); - }); - - it('should throw an error when resolver has not been set', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('noresolver'), defaultSender); - await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); - - await asyncExpectThrowRNSError(() => rns.setAddr('noresolver.rsk', rskAddr, ChainId.RSK), NO_RESOLVER); - }); - - describe('should throw an error when resolver does not support setAddr interface', () => { - it('ERC165 contract as resolver that not implements addr method', async () => { - // resolver address is the NameResolver contract, an ERC165 that not supports addr interface - const NameResolver = contract.fromABI(NameResolverData.abi, NameResolverData.bytecode); - const nameResolver = await NameResolver.new(registry.address); - - await registry.setSubnodeOwner(namehash(TLD), labelhash('anothererc165'), defaultSender); - await registry.setResolver(namehash('anothererc165.rsk'), nameResolver.address); - - await asyncExpectThrowRNSError(() => rns.setAddr('anothererc165.rsk', rskAddr, ChainId.RSK), NO_SET_CHAIN_ADDR); - }); - - it('account address as a resolver', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('accountasresolver'), defaultSender); - await registry.setResolver(namehash('accountasresolver.rsk'), defaultSender); - - await asyncExpectThrowRNSError(() => rns.setAddr('accountasresolver.rsk', rskAddr, ChainId.RSK), NO_SET_CHAIN_ADDR); - }); - }); - - it('should throw an error when domain do not exist', async () => { - await asyncExpectThrowRNSError(() => rns.setAddr('noexists.rsk', rskAddr), NO_RESOLVER); - }); - - describe('custom tx options', () => { - it('should send custom gasPrice', async () => { - const gasPrice = '70000000'; - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - const txReceipt = await rns.setAddr('alice.rsk', btcAddr, ChainId.BITCOIN, { gasPrice }); - - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); - - expect(tx.gasPrice).toEqual(gasPrice.toString()); - }); - - it('should send custom gas', async () => { - const gas = 800000; - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); - - const txReceipt = await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM, { gas }); - - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); - - expect(tx.gas).toEqual(gas); - expect(tx.from).toEqual(defaultSender); - }); - - it('should send custom sender', async () => { - const [from] = accounts; - - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), from); - - const txReceipt = await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM, { from }); - - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); - - expect(tx.from).toEqual(from); - }); - }); -}); - -describe.each([ - ['web3 mainnet', new Web3(PUBLIC_NODE_MAINNET)], - ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], - ['rsk mainnet', new Rsk3(PUBLIC_NODE_MAINNET)], - ['rsk testnet', new Rsk3(PUBLIC_NODE_TESTNET)], -])('%s - public nodes setChainAddr', (name, blockchainApiInstance) => { - test('should fail when blockchain api instance does not contain accounts to sing the tx', async () => { - const rns = new RNS(blockchainApiInstance); - await asyncExpectThrowRNSError( - () => rns.setAddr('testing.rsk', '0x0000000000000000000000000000000000000001', ChainId.ETHEREUM), - NO_ACCOUNTS_TO_SIGN, - ); - }); -}); diff --git a/test/local/setAddr.test.ts b/test/local/setAddr.test.ts new file mode 100644 index 0000000..8f3275e --- /dev/null +++ b/test/local/setAddr.test.ts @@ -0,0 +1,197 @@ +import { web3, defaultSender, accounts } from '@openzeppelin/test-environment'; +import { hash as namehash } from 'eth-ens-namehash'; +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import { + NO_RESOLVER, INVALID_ADDRESS, INVALID_CHECKSUM_ADDRESS, NO_ACCOUNTS_TO_SIGN, +} from '../../src/errors'; +import { ZERO_ADDRESS } from '../../src/constants'; +import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; +import RNS from '../../src/index'; +import { labelhash } from '../../src/utils'; +import { + deployDefinitiveResolver, deployRegistryAndCreateTldNode, getRNSInstance, + deployPublicResolver, deployMultichainResolver, +} from './helpers'; + +const web3Instance = web3 as unknown as Web3; +const rsk3Instance = new Rsk3(web3.currentProvider); + +describe.each([ + ['web3', web3Instance], + ['rsk3', rsk3Instance], +])('%s - setAddr', (name, blockchainApiInstance) => { + const addr = '0x0000000000000000000000000000000001000006'; + + let registry: any; + let publicResolver: any; + let rns: RNS; + + describe('public and multichain resolvers', () => { + beforeEach(async () => { + registry = await deployRegistryAndCreateTldNode(); + + publicResolver = await deployPublicResolver(registry); + + await registry.setResolver(namehash('rsk'), publicResolver.address); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + it('should set an address with public resolver', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', addr); + + let actualAddr = await rns.addr('alice.rsk'); + expect(actualAddr).toBe(addr); + + // set it back to zero + await rns.setAddr('alice.rsk', ZERO_ADDRESS); + + actualAddr = await publicResolver.addr(namehash('alice.rsk')); + expect(actualAddr).toEqual(ZERO_ADDRESS); + }); + + it('should set an address if implements the multichain resolver', async () => { + const multichainResolver = await deployMultichainResolver(registry, publicResolver); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + await registry.setResolver(namehash('alice.rsk'), multichainResolver.address); + + await rns.setAddr('alice.rsk', addr); + + let actualAddr = await rns.addr('alice.rsk'); + expect(actualAddr).toBe(addr); + + // set it back to zero + await rns.setAddr('alice.rsk', ZERO_ADDRESS); + + actualAddr = await multichainResolver.addr(namehash('alice.rsk')); + expect(actualAddr).toEqual(ZERO_ADDRESS); + }); + + it('should return a tx receipt when setting an address', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + const tx = await rns.setAddr('alice.rsk', addr); + + expect(tx.transactionHash).toBeTruthy(); + }); + + it('should set an address when the library is instantiated with a different networkId', async () => { + const options = { + contractAddresses: { + registry: registry.address, + }, + networkId: 18, + }; + + rns = new RNS(blockchainApiInstance, options); + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', addr); + + const actualAddr = await rns.addr('alice.rsk'); + expect(actualAddr).toBe(addr); + }); + + it('should throw an error when address is invalid', async () => { + await asyncExpectThrowRNSError(() => rns.setAddr('alice.rsk', 'invalidaddress'), INVALID_ADDRESS); + }); + + it('should throw an error when address has invalid checksum', async () => { + await asyncExpectThrowRNSError(() => rns.setAddr('alice.rsk', '0x0000000000000000000000000000000001ABcdEF'), INVALID_CHECKSUM_ADDRESS); + }); + + it('should throw an error when resolver has not been set', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolver'), defaultSender); + await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); + + await asyncExpectThrowRNSError(() => rns.setAddr('noresolver.rsk', addr), NO_RESOLVER); + }); + + it('should throw an error when domain do not exist', async () => { + await asyncExpectThrowRNSError(() => rns.setAddr('noexists.rsk', addr), NO_RESOLVER); + }); + + describe('custom tx options', () => { + it('should send custom gasPrice', async () => { + const gasPrice = '70000000'; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { gasPrice }); + + const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + + expect(tx.gasPrice).toEqual(gasPrice.toString()); + }); + + it('should send custom gas', async () => { + const gas = 80000; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { gas }); + + const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + + expect(tx.gas).toEqual(gas); + expect(tx.from).toEqual(defaultSender); + }); + + it('should send custom sender', async () => { + const [from] = accounts; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), from); + + const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { from }); + + const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + + expect(tx.from).toEqual(from); + }); + }); + }); + + describe('definitive resolver', () => { + let proxy: any; + beforeEach(async () => { + ({ registry, proxy } = await deployDefinitiveResolver()); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + it('should set an address with definitive resolver', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', addr); + + let actualAddr = await rns.addr('alice.rsk'); + expect(actualAddr).toBe(addr); + + // set it back to zero + await rns.setAddr('alice.rsk', ZERO_ADDRESS); + + actualAddr = await proxy.methods['addr(bytes32)'].call(namehash('alice.rsk')); + expect(actualAddr).toEqual(ZERO_ADDRESS); + }); + }); +}); + +describe.each([ + ['web3 mainnet', new Web3(PUBLIC_NODE_MAINNET)], + ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], + ['rsk mainnet', new Rsk3(PUBLIC_NODE_MAINNET)], + ['rsk testnet', new Rsk3(PUBLIC_NODE_TESTNET)], +])('%s - public nodes setAddr', (name, blockchainApiInstance) => { + test('should fail when blockchain api instance does not contain accounts to sign the tx', async () => { + const rns = new RNS(blockchainApiInstance); + await asyncExpectThrowRNSError( + () => rns.setAddr('testing.rsk', '0x0000000000000000000000000000000000000001'), + NO_ACCOUNTS_TO_SIGN, + ); + }); +}); diff --git a/test/local/setChainAddr.test.ts b/test/local/setChainAddr.test.ts new file mode 100644 index 0000000..6214717 --- /dev/null +++ b/test/local/setChainAddr.test.ts @@ -0,0 +1,250 @@ +import { web3, defaultSender, accounts } from '@openzeppelin/test-environment'; +import { hash as namehash } from 'eth-ens-namehash'; +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import { formatsByCoinType } from '@ensdomains/address-encoder'; +import { + NO_RESOLVER, NO_ACCOUNTS_TO_SIGN, INVALID_CHECKSUM_ADDRESS, +} from '../../src/errors'; +import { ZERO_ADDRESS } from '../../src/constants'; +import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; +import RNS from '../../src/index'; +import { ChainId } from '../../src/types'; +import { labelhash } from '../../src/utils'; +import { + deployDefinitiveResolver, deployRegistryAndCreateTldNode, + getRNSInstance, deployPublicResolver, deployMultichainResolver, +} from './helpers'; +import { CoinType } from '../../src/types/enums'; + +const web3Instance = web3 as unknown as Web3; +const rsk3Instance = new Rsk3(web3.currentProvider); + +describe.each([ + ['web3', web3Instance], + ['rsk3', rsk3Instance], +])('%s - setChainAddr', (name, blockchainApiInstance) => { + const rskAddr = '0x0000000000000000000000000000000001000006'; + const ethAddr = '0x0000000000000000000000000000000012345678'; + const btcAddr = '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2'; + + let registry: any; + let multichainResolver: any; + let rns: RNS; + + describe('public and multichain resolver', () => { + beforeEach(async () => { + registry = await deployRegistryAndCreateTldNode(); + + const publicResolver = await deployPublicResolver(registry); + multichainResolver = await deployMultichainResolver(registry, publicResolver); + + await registry.setResolver(namehash('rsk'), multichainResolver.address); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + it('should set an address for RSK', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', rskAddr, ChainId.RSK); + + let actualAddr = await rns.addr('alice.rsk', ChainId.RSK); + expect(actualAddr).toBe(rskAddr); + + // set it back to zero + await rns.setAddr('alice.rsk', ZERO_ADDRESS, ChainId.RSK); + + actualAddr = await multichainResolver.chainAddr(namehash('alice.rsk'), ChainId.RSK); + expect(actualAddr).toEqual(ZERO_ADDRESS); + }); + + it('should set an address for ETH', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM); + + let actualAddr = await rns.addr('alice.rsk', ChainId.ETHEREUM); + expect(actualAddr).toBe(ethAddr); + + // set it back to zero + await rns.setAddr('alice.rsk', ZERO_ADDRESS, ChainId.ETHEREUM); + + actualAddr = await multichainResolver.chainAddr(namehash('alice.rsk'), ChainId.ETHEREUM); + expect(actualAddr).toEqual(ZERO_ADDRESS); + }); + + it('should set an address for BTC', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', btcAddr, ChainId.BITCOIN); + + let actualAddr = await rns.addr('alice.rsk', ChainId.BITCOIN); + expect(actualAddr).toBe(btcAddr); + + // set it back to zero + await rns.setAddr('alice.rsk', '', ChainId.BITCOIN); + + actualAddr = await multichainResolver.chainAddr(namehash('alice.rsk'), ChainId.BITCOIN); + expect(actualAddr).toEqual(''); + }); + + it('should return a tx receipt when setting an address', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + const tx = await rns.setAddr('alice.rsk', rskAddr, ChainId.RSK); + + expect(tx.transactionHash).toBeTruthy(); + }); + + it('should throw an error when invalid checksum for RSK', async () => { + const address = '0x53BF4d5cF81F8c52644912cfae4d0E3EA7faDd5B'; // valid for ethereum + + await asyncExpectThrowRNSError(() => rns.setAddr('alice.rsk', address, ChainId.RSK), INVALID_CHECKSUM_ADDRESS); + }); + + it('should throw an error when invalid checksum for Ethereum', async () => { + const address = '0x53Bf4d5cF81F8c52644912cfaE4d0E3EA7FAdD5b'; // valid for rsk mainnet + + await asyncExpectThrowRNSError(() => rns.setAddr('alice.rsk', address, ChainId.ETHEREUM), INVALID_CHECKSUM_ADDRESS); + }); + + it('should throw an error when resolver has not been set', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolver'), defaultSender); + await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); + + await asyncExpectThrowRNSError(() => rns.setAddr('noresolver.rsk', rskAddr, ChainId.RSK), NO_RESOLVER); + }); + + it('should throw an error when domain do not exist', async () => { + await asyncExpectThrowRNSError(() => rns.setAddr('noexists.rsk', rskAddr), NO_RESOLVER); + }); + + describe('custom tx options', () => { + it('should send custom gasPrice', async () => { + const gasPrice = '70000000'; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + const txReceipt = await rns.setAddr('alice.rsk', btcAddr, ChainId.BITCOIN, { gasPrice }); + + const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + + expect(tx.gasPrice).toEqual(gasPrice.toString()); + }); + + it('should send custom gas', async () => { + const gas = 800000; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + const txReceipt = await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM, { gas }); + + const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + + expect(tx.gas).toEqual(gas); + expect(tx.from).toEqual(defaultSender); + }); + + it('should send custom sender', async () => { + const [from] = accounts; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), from); + + const txReceipt = await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM, { from }); + + const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + + expect(tx.from).toEqual(from); + }); + }); + }); + + describe('definitive resolver', () => { + let proxy: any; + + const getAddress = async (coinType: CoinType) => { + const decodedAddr = await proxy.methods['addr(bytes32,uint256)']( + namehash('alice.rsk'), + coinType, + ); + + if (decodedAddr) { + const buff = Buffer.from(decodedAddr.replace('0x', ''), 'hex'); + + return formatsByCoinType[coinType].encoder(buff); + } + + return decodedAddr; + }; + + beforeEach(async () => { + ({ registry, proxy } = await deployDefinitiveResolver()); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + it('should set an address for RSK', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', rskAddr, ChainId.RSK); + + let actualAddr = await getAddress(CoinType.RSK); + + expect(actualAddr).toBe(rskAddr); + + // set it back to zero + await rns.setAddr('alice.rsk', ZERO_ADDRESS, ChainId.RSK); + + actualAddr = await getAddress(CoinType.RSK); + expect(actualAddr).toBe(ZERO_ADDRESS); + }); + + it('should set an address for ETH', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM); + + let actualAddr = await getAddress(CoinType.ETHEREUM); + + expect(actualAddr).toBe(ethAddr); + + // set it back to zero + await rns.setAddr('alice.rsk', ZERO_ADDRESS, ChainId.ETHEREUM); + + actualAddr = await getAddress(CoinType.ETHEREUM); + expect(actualAddr).toBe(ZERO_ADDRESS); + }); + + it('should set an address for BTC', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setAddr('alice.rsk', btcAddr, ChainId.BITCOIN); + + let actualAddr = await getAddress(CoinType.BITCOIN); + + expect(actualAddr).toBe(btcAddr); + + // set it back to zero + await rns.setAddr('alice.rsk', '', ChainId.BITCOIN); + + actualAddr = await getAddress(CoinType.BITCOIN); + expect(actualAddr).toBe(null); + }); + }); +}); + +describe.each([ + ['web3 mainnet', new Web3(PUBLIC_NODE_MAINNET)], + ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], + ['rsk mainnet', new Rsk3(PUBLIC_NODE_MAINNET)], + ['rsk testnet', new Rsk3(PUBLIC_NODE_TESTNET)], +])('%s - public nodes setChainAddr', (name, blockchainApiInstance) => { + test('should fail when blockchain api instance does not contain accounts to sing the tx', async () => { + const rns = new RNS(blockchainApiInstance); + await asyncExpectThrowRNSError( + () => rns.setAddr('testing.rsk', '0x0000000000000000000000000000000000000001', ChainId.ETHEREUM), + NO_ACCOUNTS_TO_SIGN, + ); + }); +}); diff --git a/test/local/setContenthash.test.ts b/test/local/setContenthash.test.ts new file mode 100644 index 0000000..b3654e0 --- /dev/null +++ b/test/local/setContenthash.test.ts @@ -0,0 +1,99 @@ + +import { web3, defaultSender } from '@openzeppelin/test-environment'; +import { hash as namehash } from 'eth-ens-namehash'; +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import { + NO_RESOLVER, UNSUPPORTED_CONTENTHASH_PROTOCOL, NO_ACCOUNTS_TO_SIGN, +} from '../../src/errors'; +import { ZERO_ADDRESS } from '../../src/constants'; +import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; +import RNS from '../../src/index'; +import { labelhash } from '../../src/utils'; +import { deployDefinitiveResolver, getRNSInstance } from './helpers'; +import ContenthashHelper from '../../src/contenthash-helper'; + +const web3Instance = web3 as unknown as Web3; +const rsk3Instance = new Rsk3(web3.currentProvider); + +describe.each([ + ['web3', web3Instance], + ['rsk3', rsk3Instance], +])('%s - setContenthash', (name, blockchainApiInstance) => { + let registry: any; + let rns: RNS; + let proxy: any; + const contenthashHelper = new ContenthashHelper(); + + beforeEach(async () => { + ({ proxy, registry } = await deployDefinitiveResolver()); + + rns = getRNSInstance(blockchainApiInstance, registry); + }); + + const shouldEncodeProperly = async (contenthash: string) => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await rns.setContenthash('alice.rsk', contenthash); + + const actual = await proxy.methods['contenthash(bytes32)'](namehash('alice.rsk'), { from: defaultSender }); + + const expected = contenthash ? contenthashHelper.encodeContenthash(contenthash) : null; + expect(actual).toBe(expected); + }; + + it('should set ipfs contenthash', async () => { + const ipfsHash = 'ipfs://QmRAQB6YaCyidP37UdDnjFY5vQuiBrcqdyoW1CuDgwxkD4'; + await shouldEncodeProperly(ipfsHash); + }); + + it('should set bzz contenthash', async () => { + const swarmHash = 'bzz://d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162'; + await shouldEncodeProperly(swarmHash); + }); + + it('should set onion contenthash', async () => { + const onionHash = 'onion://zqktlwi4fecvo6ri'; + await shouldEncodeProperly(onionHash); + }); + + it('should set onion3 contenthash', async () => { + const onionHash = 'onion3://p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd'; + await shouldEncodeProperly(onionHash); + }); + + it('should set empty contenthash', async () => { + const emptyHash = ''; + await shouldEncodeProperly(emptyHash); + }); + + it('should fail if invalid contenthash', async () => { + const hash = 'onion1234://zqktlwi4fecvo6ri'; + + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); + + await asyncExpectThrowRNSError(() => rns.setContenthash('alice.rsk', hash), UNSUPPORTED_CONTENTHASH_PROTOCOL); + }); + + it('should throw an error when resolver has not been set', async () => { + await registry.setSubnodeOwner(namehash('rsk'), labelhash('noresolver'), defaultSender); + await registry.setResolver(namehash('noresolver.rsk'), ZERO_ADDRESS); + + await asyncExpectThrowRNSError(() => rns.contenthash('noresolver.rsk'), NO_RESOLVER); + }); +}); + +describe.each([ + ['web3 mainnet', new Web3(PUBLIC_NODE_MAINNET)], + ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], + ['rsk mainnet', new Rsk3(PUBLIC_NODE_MAINNET)], + ['rsk testnet', new Rsk3(PUBLIC_NODE_TESTNET)], +])('%s - setContenthash public nodes', (name, blockchainApiInstance) => { + test('should fail when web3 instance does not contain accounts to sign the tx', async () => { + const rns = new RNS(blockchainApiInstance); + await asyncExpectThrowRNSError( + () => rns.setContenthash('testing.rsk', 'check'), + NO_ACCOUNTS_TO_SIGN, + ); + }); +}); diff --git a/test/local/rns.resolve.setResolver.test.ts b/test/local/setResolver.test.ts similarity index 79% rename from test/local/rns.resolve.setResolver.test.ts rename to test/local/setResolver.test.ts index b9a87e5..1f87ad1 100644 --- a/test/local/rns.resolve.setResolver.test.ts +++ b/test/local/setResolver.test.ts @@ -1,6 +1,5 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; import { - contract, web3, defaultSender, accounts, + web3, defaultSender, accounts, } from '@openzeppelin/test-environment'; import { hash as namehash } from 'eth-ens-namehash'; import Web3 from 'web3'; @@ -12,8 +11,8 @@ import { asyncExpectThrowRNSError, asyncExpectThrowVMRevert, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET, } from '../utils'; import RNS from '../../src/index'; -import { Options } from '../../src/types'; import { labelhash } from '../../src/utils'; +import { deployRegistryAndCreateTldNode, getRNSInstance } from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -22,32 +21,19 @@ describe.each([ ['web3', web3Instance], ['rsk3', rsk3Instance], ])('%s - setResolver', (name, blockchainApiInstance) => { - const TLD = 'rsk'; - let registry: any; let rns: RNS; - let options: Options; beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - - registry = await Registry.new(); - - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); - - options = { - contractAddresses: { - registry: registry.address, - }, - }; + registry = await deployRegistryAndCreateTldNode(); - rns = new RNS(blockchainApiInstance, options); + rns = getRNSInstance(blockchainApiInstance, registry); }); it('should set a resolver address', async () => { const addr = '0x0000000000000000000000000000000001000006'; - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); await rns.setResolver('alice.rsk', addr); @@ -58,7 +44,7 @@ describe.each([ it('should return a tx receipt', async () => { const addr = '0x0000000000000000000000000000000001000006'; - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); const tx = await rns.setResolver('alice.rsk', addr); @@ -79,7 +65,7 @@ describe.each([ it('should VM revert when domain is not owned by the sender', async () => { const [account] = accounts; - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), account); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), account); await asyncExpectThrowVMRevert(() => rns.setResolver('alice.rsk', '0x0000000000000000000000000000000001000006')); }); @@ -90,7 +76,7 @@ describe.each([ it('should send custom gasPrice', async () => { const gasPrice = '70000000'; - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); const txReceipt = await rns.setResolver('alice.rsk', addr, { gasPrice }); @@ -102,7 +88,7 @@ describe.each([ it('should send custom gas', async () => { const gas = 80000; - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); const txReceipt = await rns.setResolver('alice.rsk', addr, { gas }); @@ -115,7 +101,7 @@ describe.each([ it('should send custom sender', async () => { const [from] = accounts; - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), from); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), from); const txReceipt = await rns.setResolver('alice.rsk', addr, { from }); diff --git a/test/local/rns.resolve.setReverse.test.ts b/test/local/setReverse.test.ts similarity index 79% rename from test/local/rns.resolve.setReverse.test.ts rename to test/local/setReverse.test.ts index 986865d..c0f380f 100644 --- a/test/local/rns.resolve.setReverse.test.ts +++ b/test/local/setReverse.test.ts @@ -1,9 +1,4 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import NameResolverData from '@rsksmart/rns-reverse/NameResolverData.json'; -import ReverseRegistrarData from '@rsksmart/rns-reverse/ReverseRegistrarData.json'; -import { - contract, web3, defaultSender, accounts, -} from '@openzeppelin/test-environment'; +import { web3, defaultSender, accounts } from '@openzeppelin/test-environment'; import { hash as namehash } from 'eth-ens-namehash'; import Web3 from 'web3'; import Rsk3 from '@rsksmart/rsk3'; @@ -12,9 +7,11 @@ import { } from '../../src/errors'; import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; import RNS from '../../src/index'; -import { Options } from '../../src/types'; import { labelhash } from '../../src/utils'; import { ZERO_ADDRESS } from '../../src/constants'; +import { + deployRegistryAndCreateTldNode, getRNSInstance, deployNameResolver, deployReverseRegistrar, +} from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -27,31 +24,18 @@ describe.each([ let nameResolver: any; let reverseRegistrar: any; let rns: RNS; - let options: Options; beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const NameResolver = contract.fromABI(NameResolverData.abi, NameResolverData.bytecode); - const ReverseRegistrar = contract.fromABI( - ReverseRegistrarData.abi, - ReverseRegistrarData.bytecode, - ); + registry = await deployRegistryAndCreateTldNode(); - registry = await Registry.new(); - nameResolver = await NameResolver.new(registry.address); - reverseRegistrar = await ReverseRegistrar.new(registry.address); + nameResolver = await deployNameResolver(registry); + reverseRegistrar = await deployReverseRegistrar(registry); await registry.setSubnodeOwner('0x00', labelhash('reverse'), defaultSender); await registry.setResolver(namehash('reverse'), nameResolver.address); await registry.setSubnodeOwner(namehash('reverse'), labelhash('addr'), reverseRegistrar.address); - options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); + rns = getRNSInstance(blockchainApiInstance, registry); }); it('should set reverse resolution of an address', async () => { diff --git a/test/local/rns.setup.test.ts b/test/local/setup.test.ts similarity index 84% rename from test/local/rns.setup.test.ts rename to test/local/setup.test.ts index ae4653f..89e99a0 100644 --- a/test/local/rns.setup.test.ts +++ b/test/local/setup.test.ts @@ -1,5 +1,5 @@ import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import { contract, web3 } from '@openzeppelin/test-environment'; +import { web3 } from '@openzeppelin/test-environment'; import Web3 from 'web3'; import Rsk3 from '@rsksmart/rsk3'; import { LIBRARY_NOT_COMPOSED, NO_ADDRESSES_PROVIDED } from '../../src/errors'; @@ -9,6 +9,7 @@ import { } from '../utils'; import RNS from '../../src/index'; import { NetworkId } from '../../src/types'; +import { deployRegistryAndCreateTldNode, getRNSInstance } from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -18,17 +19,12 @@ describe.each([ ['rsk3', rsk3Instance], ])('%s - library setup', (name, blockchainApiInstance) => { it('should set custom address if provided', async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const registry = await Registry.new(); - const registryAddress = registry.address; - const options = { - contractAddresses: { registry: registryAddress }, - }; + const registry = await deployRegistryAndCreateTldNode(); - const rns = new RNS(blockchainApiInstance, options); + const rns = getRNSInstance(blockchainApiInstance, registry); await rns.compose(); - expect(rns.contracts.registry.options.address).toBe(registryAddress); + expect(rns.contracts.registry.options.address).toBe(registry.address); }); it('should fail when getting contracts if library not composed', () => { @@ -41,10 +37,10 @@ describe.each([ expectThrowRNSError(() => rns.currentNetworkId, LIBRARY_NOT_COMPOSED); }); - it('should fail when compose if invalid network', async () => { + it('should fail when compose if invalid network', () => { const invalidWeb3 = new Web3('https://invalid.rsk.co'); const rns = new RNS(invalidWeb3); - await asyncExpectThrowError(() => rns.compose()); + asyncExpectThrowError(() => rns.compose()); }); it('should fail when compose if custom network and no addresses provided', async () => { diff --git a/test/local/rns.subdomains.available.test.ts b/test/local/subdomains.available.test.ts similarity index 80% rename from test/local/rns.subdomains.available.test.ts rename to test/local/subdomains.available.test.ts index b42501d..46636b7 100644 --- a/test/local/rns.subdomains.available.test.ts +++ b/test/local/subdomains.available.test.ts @@ -1,7 +1,4 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import { - contract, web3, defaultSender, -} from '@openzeppelin/test-environment'; +import { web3, defaultSender } from '@openzeppelin/test-environment'; import { hash as namehash } from 'eth-ens-namehash'; import Web3 from 'web3'; import Rsk3 from '@rsksmart/rsk3'; @@ -10,8 +7,8 @@ import { } from '../../src/errors'; import { asyncExpectThrowRNSError } from '../utils'; import RNS from '../../src/index'; -import { Options } from '../../src/types'; import { labelhash } from '../../src/utils'; +import { deployRegistryAndCreateTldNode, getRNSInstance } from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -20,31 +17,18 @@ describe.each([ ['web3', web3Instance], ['rsk3', rsk3Instance], ])('%s - subdomains.available', (name, blockchainApiInstance) => { - const TLD = 'rsk'; - let registry: any; let rns: RNS; - let options: Options; beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - - registry = await Registry.new(); - - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); - - options = { - contractAddresses: { - registry: registry.address, - }, - }; + registry = await deployRegistryAndCreateTldNode(); - rns = new RNS(blockchainApiInstance, options); + rns = getRNSInstance(blockchainApiInstance, registry); }); describe('validations', () => { it('should not fail when sending a subdomain', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); await registry.setSubnodeOwner(namehash('alice.rsk'), labelhash('subdomain'), defaultSender); const available = await rns.subdomains.available('subdomain.alice.rsk', 'check'); expect(available).toBe(true); @@ -94,13 +78,13 @@ describe.each([ describe('subdomains.available happy paths', () => { it('should return true if label is available', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); const available = await rns.subdomains.available('alice.rsk', 'check'); expect(available).toBe(true); }); it('should return false if label is not available', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); await registry.setSubnodeOwner(namehash('alice.rsk'), labelhash('test'), defaultSender); const available = await rns.subdomains.available('alice.rsk', 'test'); expect(available).toBe(false); diff --git a/test/local/rns.subdomains.create.test.ts b/test/local/subdomains.create.test.ts similarity index 90% rename from test/local/rns.subdomains.create.test.ts rename to test/local/subdomains.create.test.ts index 666eeb9..57137f5 100644 --- a/test/local/rns.subdomains.create.test.ts +++ b/test/local/subdomains.create.test.ts @@ -1,9 +1,5 @@ import Web3 from 'web3'; -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; -import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; -import { - accounts, contract, web3, defaultSender, -} from '@openzeppelin/test-environment'; +import { accounts, web3, defaultSender } from '@openzeppelin/test-environment'; import { hash as namehash } from 'eth-ens-namehash'; import Rsk3 from '@rsksmart/rsk3'; import { TransactionReceipt } from 'web3-eth'; @@ -19,6 +15,9 @@ import { } from '../../src/errors'; import { labelhash } from '../../src/utils'; import { ZERO_ADDRESS } from '../../src/constants'; +import { + deployRegistryAndCreateTldNode, getRNSInstance, deployPublicResolver, +} from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -27,8 +26,6 @@ describe.each([ ['web3', web3Instance], ['rsk3', rsk3Instance], ])('%s - subdomains.create', (name, blockchainApiInstance) => { - const TLD = 'rsk'; - let registry: any; let publicResolver: any; let rns: RNS; @@ -36,26 +33,18 @@ describe.each([ const [owner] = accounts; beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - const PublicResolver = contract.fromABI(AddrResolverData.abi, AddrResolverData.bytecode); - registry = await Registry.new(); - publicResolver = await PublicResolver.new(registry.address); + registry = await deployRegistryAndCreateTldNode(); - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); + publicResolver = await deployPublicResolver(registry); - await registry.setResolver(namehash(TLD), publicResolver.address); + await registry.setResolver(namehash('rsk'), publicResolver.address); - options = { - contractAddresses: { - registry: registry.address, - }, - }; - rns = new RNS(blockchainApiInstance, options); + rns = getRNSInstance(blockchainApiInstance, registry); }); describe('validations', () => { it('should not fail when sending a subdomain', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); await registry.setSubnodeOwner(namehash('alice.rsk'), labelhash('subdomain'), defaultSender); await rns.subdomains.create('subdomain.alice.rsk', 'check', owner); }); diff --git a/test/local/rns.subdomains.setOwner.test.ts b/test/local/subdomains.setOwner.test.ts similarity index 91% rename from test/local/rns.subdomains.setOwner.test.ts rename to test/local/subdomains.setOwner.test.ts index 311744d..2984246 100644 --- a/test/local/rns.subdomains.setOwner.test.ts +++ b/test/local/subdomains.setOwner.test.ts @@ -1,6 +1,5 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; import { - accounts, contract, web3, defaultSender, + accounts, web3, defaultSender, } from '@openzeppelin/test-environment'; import { hash as namehash } from 'eth-ens-namehash'; import Web3 from 'web3'; @@ -12,9 +11,11 @@ import { } from '../utils'; import { INVALID_DOMAIN, SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS, - DOMAIN_NOT_EXISTS, INVALID_LABEL, NO_ACCOUNTS_TO_SIGN, INVALID_CHECKSUM_ADDRESS, INVALID_ADDRESS, + DOMAIN_NOT_EXISTS, INVALID_LABEL, NO_ACCOUNTS_TO_SIGN, + INVALID_CHECKSUM_ADDRESS, INVALID_ADDRESS, } from '../../src/errors'; import { labelhash } from '../../src/utils'; +import { deployRegistryAndCreateTldNode, getRNSInstance } from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -23,27 +24,15 @@ describe.each([ ['web3', web3Instance], ['rsk3', rsk3Instance], ])('%s - subdomains.setOwner', (name, blockchainApiInstance) => { - const TLD = 'rsk'; - let registry: any; let rns: RNS; let options: Options; const [owner] = accounts; beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - - registry = await Registry.new(); - - await registry.setSubnodeOwner('0x00', labelhash(TLD), defaultSender); + registry = await deployRegistryAndCreateTldNode(); - options = { - contractAddresses: { - registry: registry.address, - }, - }; - - rns = new RNS(blockchainApiInstance, options); + rns = getRNSInstance(blockchainApiInstance, registry); }); describe('validations', () => { @@ -67,7 +56,7 @@ describe.each([ }); it('should not fail when sending a subdomain', async () => { - await registry.setSubnodeOwner(namehash(TLD), labelhash('alice'), defaultSender); + await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); await registry.setSubnodeOwner(namehash('alice.rsk'), labelhash('subdomain'), defaultSender); await rns.subdomains.setOwner('subdomain.alice.rsk', 'check', owner); }); diff --git a/test/local/rns.utils.test.ts b/test/local/utils.test.ts similarity index 98% rename from test/local/rns.utils.test.ts rename to test/local/utils.test.ts index 7371596..49e5cd1 100644 --- a/test/local/rns.utils.test.ts +++ b/test/local/utils.test.ts @@ -1,4 +1,3 @@ -import RNSRegistryData from '@rsksmart/rns-registry/RNSRegistryData.json'; import AddrResolverData from '@rsksmart/rns-resolver/AddrResolverData.json'; import { contract, web3, accounts } from '@openzeppelin/test-environment'; import Web3 from 'web3'; @@ -8,6 +7,7 @@ import Rsk3 from '@rsksmart/rsk3'; import RNS from '../../src/index'; import { Options, NetworkId } from '../../src/types'; import { ADDR_INTERFACE } from '../../src/constants'; +import { deployRegistryAndCreateTldNode } from './helpers'; const web3Instance = web3 as unknown as Web3; const rsk3Instance = new Rsk3(web3.currentProvider); @@ -21,9 +21,7 @@ describe.each([ let options: Options; beforeEach(async () => { - const Registry = contract.fromABI(RNSRegistryData.abi, RNSRegistryData.bytecode); - - registry = await Registry.new(); + registry = await deployRegistryAndCreateTldNode(); options = { contractAddresses: { diff --git a/test/public-nodes/addr.test.ts b/test/public-nodes/addr.test.ts new file mode 100644 index 0000000..3937cdb --- /dev/null +++ b/test/public-nodes/addr.test.ts @@ -0,0 +1,69 @@ +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import RNS from '../../src/index'; +import { NO_ADDR_RESOLUTION_SET, NO_RESOLVER, NO_ADDR_RESOLUTION } from '../../src/errors'; +import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; + +describe.each([ + ['web3 mainnet', new Web3(PUBLIC_NODE_MAINNET)], + ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], + ['rsk3 mainnet', new Rsk3(PUBLIC_NODE_MAINNET)], + ['rsk3 testnet', new Rsk3(PUBLIC_NODE_TESTNET)], +])('%s - addr resolution', (name, blockchainApiInstance) => { + let rns: RNS; + + beforeEach(() => { + rns = new RNS(blockchainApiInstance); + }); + + it('should resolve a name with public resolver', async () => { + const addr = await rns.addr('testing.rsk'); + expect(addr).toBe('0x0000000000000000000000000000000001000006'); + }); + + it('should throw an error when resolver has not been set', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noresolver.testing.rsk'), NO_RESOLVER); + }); + + it('should throw an error when resolver does not implement addr interface', async () => { + // resolver address is the NameResolver contract. an ERC165 that not supports addr interface + await asyncExpectThrowRNSError(() => rns.addr('noaddrresolver.testing.rsk'), NO_ADDR_RESOLUTION); + }); + + it('should throw an error when no resolution set with public resolver', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noresolution.testing.rsk'), NO_ADDR_RESOLUTION_SET); + }); + + it('should throw an error when no resolution set with multichain resolver', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noresolution.multichain.testing.rsk'), NO_ADDR_RESOLUTION_SET); + }); + + it('should throw an error when domain do not exist', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noexists.testing.rsk'), NO_RESOLVER); + }); +}); + +describe.each([ + ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], + ['rsk3 testnet', new Rsk3(PUBLIC_NODE_TESTNET)], +])('%s - addr resolution only testnet', (name, blockchainApiInstance) => { + let rns: RNS; + + beforeEach(() => { + rns = new RNS(blockchainApiInstance); + }); + + it('should resolve a name with multichain resolver', async () => { + const addr = await rns.addr('multichain.testing.rsk'); + expect(addr).toBe('0x0000000000000000000000000000000001000006'); + }); + + it('should resolve a name with definitive resolver', async () => { + const addr = await rns.addr('addr.definitive.testing.rsk'); + expect(addr).toBe('0x0000000000000000000000000000000001000006'); + }); + + it('should throw an error when no resolution set with definitive resolver', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noresolution.definitive.testing.rsk'), NO_ADDR_RESOLUTION_SET); + }); +}); diff --git a/test/public-nodes/rns.available.test.ts b/test/public-nodes/available.test.ts similarity index 100% rename from test/public-nodes/rns.available.test.ts rename to test/public-nodes/available.test.ts diff --git a/test/public-nodes/chainAddr.test.ts b/test/public-nodes/chainAddr.test.ts new file mode 100644 index 0000000..a496520 --- /dev/null +++ b/test/public-nodes/chainAddr.test.ts @@ -0,0 +1,71 @@ +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import RNS from '../../src/index'; +import { NO_CHAIN_ADDR_RESOLUTION, NO_RESOLVER, NO_CHAIN_ADDR_RESOLUTION_SET } from '../../src/errors'; +import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; +import { ChainId } from '../../src/types'; + +describe.each([ + ['web3 mainnet', new Web3(PUBLIC_NODE_MAINNET)], + ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], + ['rsk3 mainnet', new Rsk3(PUBLIC_NODE_MAINNET)], + ['rsk3 testnet', new Rsk3(PUBLIC_NODE_TESTNET)], +])('%s - chainAddr resolution', (name, blockchainApiInstance) => { + let rns: RNS; + + beforeEach(() => { + rns = new RNS(blockchainApiInstance); + }); + + it('should resolve a name for BTC with multichain resolver', async () => { + const addr = await rns.addr('multichain.testing.rsk', ChainId.BITCOIN); + expect(addr).toBe('1Ftu4C8VW18RkB8PZxXwwHocMLyEynLcrG'); + }); + + it('should resolve a name for ETH with multichain resolver', async () => { + const addr = await rns.addr('multichain.testing.rsk', ChainId.ETHEREUM); + expect(addr).toBe('0x0000000000000000000000000000000001000006'); + }); + + it('should throw an error when resolver has not been set', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noresolver.multichain.testing.rsk', ChainId.BITCOIN), NO_RESOLVER); + }); + + it('should throw an error when resolver does not implement chainAddr nor addr interface', async () => { + // resolver address is the NameResolver contract. an ERC165 that not supports addr interface + await asyncExpectThrowRNSError(() => rns.addr('nochainaddrresolver.multichain.testing.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION); + }); + + it('should throw an error when no resolution set with multichain resolver', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noresolution.multichain.testing.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION_SET); + }); + + it('should throw an error when domain do not exist', async () => { + await asyncExpectThrowRNSError(() => rns.addr('noexists.multichain.testing.rsk', ChainId.BITCOIN), NO_RESOLVER); + }); +}); + +describe.each([ + ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], + ['rsk3 testnet', new Rsk3(PUBLIC_NODE_TESTNET)], +])('%s - chainAddr resolution only testnet', (name, blockchainApiInstance) => { + let rns: RNS; + + beforeEach(() => { + rns = new RNS(blockchainApiInstance); + }); + + it('should throw an error when no resolution set with definitive resolver', async () => { + await asyncExpectThrowRNSError(() => rns.addr('multi.definitive.testing.rsk', ChainId.LITECOIN), NO_CHAIN_ADDR_RESOLUTION_SET); + }); + + it('should resolve a name for BTC with definitive resolver', async () => { + const addr = await rns.addr('multi.definitive.testing.rsk', ChainId.BITCOIN); + expect(addr).toBe('1Ftu4C8VW18RkB8PZxXwwHocMLyEynLcrG'); + }); + + it('should resolve a name for ETH with definitive resolver', async () => { + const addr = await rns.addr('multi.definitive.testing.rsk', ChainId.ETHEREUM); + expect(addr).toBe('0x0000000000000000000000000000000001000006'); + }); +}); diff --git a/test/public-nodes/contenthash.test.ts b/test/public-nodes/contenthash.test.ts new file mode 100644 index 0000000..57dd039 --- /dev/null +++ b/test/public-nodes/contenthash.test.ts @@ -0,0 +1,42 @@ +import Web3 from 'web3'; +import Rsk3 from '@rsksmart/rsk3'; +import RNS from '../../src/index'; +import { + NO_RESOLVER, NO_CONTENTHASH_INTERFACE, NO_CONTENTHASH_SET, +} from '../../src/errors'; +import { asyncExpectThrowRNSError, PUBLIC_NODE_TESTNET } from '../utils'; + +describe.each([ + ['web3 testnet', new Web3(PUBLIC_NODE_TESTNET)], + ['rsk3 testnet', new Rsk3(PUBLIC_NODE_TESTNET)], +])('%s - contenthash resolution', (name, blockchainApiInstance) => { + let rns: RNS; + + beforeEach(() => { + rns = new RNS(blockchainApiInstance); + }); + + it('should resolve a contenthash', async () => { + const contenthash = await rns.contenthash('definitive.testing.rsk'); + + expect(contenthash.decoded).toBe('QmRAQB6YaCyidP37UdDnjFY5vQuiBrcqdyoW1CuDgwxkD4'); + expect(contenthash.protocolType).toBe('ipfs'); + }); + + it('should throw an error when resolver has not been set', async () => { + await asyncExpectThrowRNSError(() => rns.contenthash('noresolver.testing.rsk'), NO_RESOLVER); + }); + + it('should throw an error when resolver does not implement contenthash interface', async () => { + // resolver address is the NameResolver contract. an ERC165 that not supports addr interface + await asyncExpectThrowRNSError(() => rns.contenthash('noaddrresolver.testing.rsk'), NO_CONTENTHASH_INTERFACE); + }); + + it('should throw an error when no contenthash', async () => { + await asyncExpectThrowRNSError(() => rns.contenthash('addr.definitive.testing.rsk'), NO_CONTENTHASH_SET); + }); + + it('should throw an error when domain do not exist', async () => { + await asyncExpectThrowRNSError(() => rns.contenthash('noexists.testing.rsk'), NO_RESOLVER); + }); +}); diff --git a/test/public-nodes/rns.resolve.name.test.ts b/test/public-nodes/reverse.test.ts similarity index 72% rename from test/public-nodes/rns.resolve.name.test.ts rename to test/public-nodes/reverse.test.ts index 676137e..72e55ad 100644 --- a/test/public-nodes/rns.resolve.name.test.ts +++ b/test/public-nodes/reverse.test.ts @@ -16,21 +16,13 @@ describe.each([ rns = new RNS(blockchainApiInstance); }); - test('should resolve an address', async () => { + it('should resolve an address', async () => { const name = await rns.reverse('0xe9a4e6fae8217E032A08848E227d2b57D3E1e0A5'); expect(name).toBe('testing.rsk'); }); - describe('should throw an error when invalid ERC165 contract (account address) as reverse resolver', () => { - test('testnet', async () => { - const web3 = new Web3(PUBLIC_NODE_TESTNET); - rns = new RNS(web3); - await asyncExpectThrowRNSError(() => rns.reverse('0x799c63A0bd1FaB0D7E784f35766FB496766BB245'), NO_NAME_RESOLUTION); - }); - }); - describe('should throw an error when ERC165 that not support name interface (public resolver) as reverse resolver', () => { - test('testnet', async () => { + it('testnet', async () => { const web3 = new Web3(PUBLIC_NODE_TESTNET); rns = new RNS(web3); await asyncExpectThrowRNSError(() => rns.reverse('0x1c0884e81161B526f6A4baBC557F97649a2c74CC'), NO_NAME_RESOLUTION); @@ -38,14 +30,14 @@ describe.each([ }); describe('should throw an error when the address has a resolver but no resolution set', () => { - test('testnet', async () => { + it('testnet', async () => { const web3 = new Web3(PUBLIC_NODE_TESTNET); rns = new RNS(web3); await asyncExpectThrowRNSError(() => rns.reverse('0x0BC10AFD0Fc8344Ac3bBDDEE72221F148Ee0Bc61'), NO_REVERSE_RESOLUTION_SET); }); }); - test('should throw an error when reverse resolution has not been set', async () => { + it('should throw an error when reverse resolution has not been set', async () => { await asyncExpectThrowRNSError(() => rns.reverse('0x0000000000000000000000000000000000000001'), NO_REVERSE_RESOLUTION_SET); }); }); diff --git a/test/public-nodes/rns.resolve.addr.test.ts b/test/public-nodes/rns.resolve.addr.test.ts deleted file mode 100644 index 6107895..0000000 --- a/test/public-nodes/rns.resolve.addr.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import Web3 from 'web3'; -import Rsk3 from '@rsksmart/rsk3'; -import RNS from '../../src/index'; -import { NO_ADDR_RESOLUTION_SET, NO_RESOLVER, NO_ADDR_RESOLUTION } from '../../src/errors'; -import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; - -describe.each([ - new Web3(PUBLIC_NODE_MAINNET), - new Web3(PUBLIC_NODE_TESTNET), - new Rsk3(PUBLIC_NODE_MAINNET), - new Rsk3(PUBLIC_NODE_TESTNET), -])('addr resolution', (blockchainApiInstance) => { - let rns: RNS; - - beforeEach(() => { - rns = new RNS(blockchainApiInstance); - }); - - test('should resolve a name', async () => { - const addr = await rns.addr('testing.rsk'); - expect(addr).toBe('0x0000000000000000000000000000000001000006'); - }); - - test('should throw an error when resolver has not been set', async () => { - await asyncExpectThrowRNSError(() => rns.addr('noresolver.testing.rsk'), NO_RESOLVER); - }); - - describe('should throw an error when resolver does not support addr interface', () => { - test('ERC165 contract as resolver that not implements addr method', async () => { - // resolver address is the NameResolver contract. an ERC165 that not supports addr interface - await asyncExpectThrowRNSError(() => rns.addr('noaddrresolver.testing.rsk'), NO_ADDR_RESOLUTION); - }); - - test('non contract address as a resolver', async () => { - await asyncExpectThrowRNSError(() => rns.addr('accountasresolver.testing.rsk'), NO_ADDR_RESOLUTION); - }); - }); - - test('should throw an error when no resolution set', async () => { - await asyncExpectThrowRNSError(() => rns.addr('noresolution.testing.rsk'), NO_ADDR_RESOLUTION_SET); - }); - - test('should throw an error when domain do not exist', async () => { - await asyncExpectThrowRNSError(() => rns.addr('noexists.testing.rsk'), NO_RESOLVER); - }); -}); diff --git a/test/public-nodes/rns.resolve.chainAddr.test.ts b/test/public-nodes/rns.resolve.chainAddr.test.ts deleted file mode 100644 index 478727e..0000000 --- a/test/public-nodes/rns.resolve.chainAddr.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import Web3 from 'web3'; -import Rsk3 from '@rsksmart/rsk3'; -import RNS from '../../src/index'; -import { NO_CHAIN_ADDR_RESOLUTION, NO_RESOLVER, NO_CHAIN_ADDR_RESOLUTION_SET } from '../../src/errors'; -import { asyncExpectThrowRNSError, PUBLIC_NODE_MAINNET, PUBLIC_NODE_TESTNET } from '../utils'; -import { ChainId } from '../../src/types'; - -describe.each([ - new Web3(PUBLIC_NODE_MAINNET), - new Web3(PUBLIC_NODE_TESTNET), - new Rsk3(PUBLIC_NODE_MAINNET), - new Rsk3(PUBLIC_NODE_TESTNET), -])('chainAddr resolution', (blockchainApiInstance) => { - let rns: RNS; - - beforeEach(() => { - rns = new RNS(blockchainApiInstance); - }); - - test('should resolve a name for BTC', async () => { - const addr = await rns.addr('multichain.testing.rsk', ChainId.BITCOIN); - expect(addr).toBe('1Ftu4C8VW18RkB8PZxXwwHocMLyEynLcrG'); - }); - - test('should resolve a name for ETH', async () => { - const addr = await rns.addr('multichain.testing.rsk', ChainId.ETHEREUM); - expect(addr).toBe('0x0000000000000000000000000000000001000006'); - }); - - test('should throw an error when resolver has not been set', async () => { - await asyncExpectThrowRNSError(() => rns.addr('noresolver.multichain.testing.rsk', ChainId.BITCOIN), NO_RESOLVER); - }); - - describe('should throw an error when resolver does not support chain addr interface', () => { - test('ERC165 contract as resolver that not implements addr method', async () => { - // resolver address is the NameResolver contract. an ERC165 that not supports addr interface - await asyncExpectThrowRNSError(() => rns.addr('nochainaddrresolver.multichain.testing.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION); - }); - - test('non contract address as a resolver', async () => { - await asyncExpectThrowRNSError(() => rns.addr('accountasresolver.multichain.testing.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION); - }); - }); - - test('should throw an error when no resolution set', async () => { - await asyncExpectThrowRNSError(() => rns.addr('noresolution.multichain.testing.rsk', ChainId.BITCOIN), NO_CHAIN_ADDR_RESOLUTION_SET); - }); - - test('should throw an error when domain do not exist', async () => { - await asyncExpectThrowRNSError(() => rns.addr('noexists.multichain.testing.rsk', ChainId.BITCOIN), NO_RESOLVER); - }); -}); diff --git a/test/public-nodes/rns.resolve.setAddr.test.ts b/test/public-nodes/setAddr.test.ts similarity index 87% rename from test/public-nodes/rns.resolve.setAddr.test.ts rename to test/public-nodes/setAddr.test.ts index e236e12..18fd51d 100644 --- a/test/public-nodes/rns.resolve.setAddr.test.ts +++ b/test/public-nodes/setAddr.test.ts @@ -10,7 +10,7 @@ describe.each([ new Rsk3(PUBLIC_NODE_MAINNET), new Rsk3(PUBLIC_NODE_TESTNET), ])('rns.setAddr', (blockchainApiInstance) => { - test('should fail when web3 instance does not contain accounts to sing the tx', async () => { + it('should fail when web3 instance does not contain accounts to sing the tx', async () => { const rns = new RNS(blockchainApiInstance); await asyncExpectThrowRNSError( diff --git a/test/public-nodes/rns.resolve.setResolver.test.ts b/test/public-nodes/setResolver.test.ts similarity index 87% rename from test/public-nodes/rns.resolve.setResolver.test.ts rename to test/public-nodes/setResolver.test.ts index 5a2c0c3..7ac28b1 100644 --- a/test/public-nodes/rns.resolve.setResolver.test.ts +++ b/test/public-nodes/setResolver.test.ts @@ -10,7 +10,7 @@ describe.each([ new Rsk3(PUBLIC_NODE_MAINNET), new Rsk3(PUBLIC_NODE_TESTNET), ])('rns.setResolver', (blockchainApiInstance) => { - test('should fail when web3 instance does not contain accounts to sign the tx', async () => { + it('should fail when web3 instance does not contain accounts to sign the tx', async () => { const rns = new RNS(blockchainApiInstance); await asyncExpectThrowRNSError( () => rns.setResolver('multichain.testing.rsk', '0x0000000000000000000000000000000000000001'), diff --git a/test/public-nodes/rns.setup.test.ts b/test/public-nodes/setup.test.ts similarity index 88% rename from test/public-nodes/rns.setup.test.ts rename to test/public-nodes/setup.test.ts index c679780..5436046 100644 --- a/test/public-nodes/rns.setup.test.ts +++ b/test/public-nodes/setup.test.ts @@ -14,14 +14,14 @@ describe('library setup', () => { contractAddresses: { registry: registryAddress }, }; - test('mainnet', async () => { + it('mainnet', async () => { const web3 = new Web3(PUBLIC_NODE_MAINNET); const rns = new RNS(web3, options); await rns.compose(); expect(rns.contracts.registry.options.address.toLowerCase()).toBe(registryAddress); }); - test('testnet', async () => { + it('testnet', async () => { const web3 = new Web3(PUBLIC_NODE_TESTNET); const rns = new RNS(web3, options); await rns.compose(); @@ -30,7 +30,7 @@ describe('library setup', () => { }); describe('should return registry address after compose', () => { - test('mainnet', async () => { + it('mainnet', async () => { const web3 = new Web3(PUBLIC_NODE_MAINNET); const rns = new RNS(web3); await rns.compose(); @@ -38,7 +38,7 @@ describe('library setup', () => { .toBe(RNSRegistryData.address.rskMainnet); }); - test('testnet', async () => { + it('testnet', async () => { const web3 = new Web3(PUBLIC_NODE_TESTNET); const rns = new RNS(web3); await rns.compose(); @@ -48,14 +48,14 @@ describe('library setup', () => { }); describe('should return networkId after compose', () => { - test('mainnet', async () => { + it('mainnet', async () => { const web3 = new Web3(PUBLIC_NODE_MAINNET); const rns = new RNS(web3); await rns.compose(); expect(rns.currentNetworkId).toBe(NetworkId.RSK_MAINNET); }); - test('testnet', async () => { + it('testnet', async () => { const web3 = new Web3(PUBLIC_NODE_TESTNET); const rns = new RNS(web3); await rns.compose(); @@ -64,20 +64,20 @@ describe('library setup', () => { }); describe('should fail when getting contracts if library not composed', () => { - test('mainnet', () => { + it('mainnet', () => { const web3 = new Web3(PUBLIC_NODE_MAINNET); const rns = new RNS(web3); expectThrowRNSError(() => rns.contracts, LIBRARY_NOT_COMPOSED); }); - test('testnet', () => { + it('testnet', () => { const web3 = new Web3(PUBLIC_NODE_TESTNET); const rns = new RNS(web3); expectThrowRNSError(() => rns.contracts, LIBRARY_NOT_COMPOSED); }); }); - test('should fail when compose if invalid network', async () => { + it('should fail when compose if invalid network', async () => { const web3 = new Web3('https://invalid.rsk.co'); const rns = new RNS(web3); await asyncExpectThrowError(() => rns.compose()); diff --git a/test/public-nodes/rns.subdomains.available.test.ts b/test/public-nodes/subdomains.available.test.ts similarity index 71% rename from test/public-nodes/rns.subdomains.available.test.ts rename to test/public-nodes/subdomains.available.test.ts index 88799fb..50c355d 100644 --- a/test/public-nodes/rns.subdomains.available.test.ts +++ b/test/public-nodes/subdomains.available.test.ts @@ -19,60 +19,60 @@ describe.each([ }); describe('validations', () => { - test('should not fail when sending a subdomain', async () => { + it('should not fail when sending a subdomain', async () => { const available = await rns.subdomains.available('multichain.testing.rsk', 'check'); expect(available).toBe(true); }); - test('should not fail when sending just a tld', async () => { + it('should not fail when sending just a tld', async () => { const available = await rns.subdomains.available('rsk', 'testing'); expect(available).toBe(false); }); - test('should fail when sending an empty domain', async () => { + it('should fail when sending an empty domain', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('', 'willfail'), INVALID_DOMAIN); }); - test('should fail when sending an just a dot with no labels', async () => { + it('should fail when sending an just a dot with no labels', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('.', 'willfail'), INVALID_DOMAIN); }); - test('should fail when not sending an .rsk domain', async () => { + it('should fail when not sending an .rsk domain', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('domain.notrsk', 'willfail'), SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS); }); - test('should fail when sending upper case domain', async () => { + it('should fail when sending upper case domain', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('DOMAIN.rsk', 'willfail'), INVALID_DOMAIN); }); - test('should fail when sending invalid characters', async () => { + it('should fail when sending invalid characters', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('DOM-AIN.rsk', 'willfail'), INVALID_DOMAIN); }); - test('should fail when given domain does not exist', async () => { + it('should fail when given domain does not exist', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('noexists.rsk', 'willfail'), DOMAIN_NOT_EXISTS); }); - test('should fail when sending empty label', async () => { + it('should fail when sending empty label', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('domain.rsk', ''), INVALID_LABEL); }); - test('should fail when sending label with upper case characters', async () => { + it('should fail when sending label with upper case characters', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('domain.rsk', 'iNVAlid'), INVALID_LABEL); }); - test('should fail when sending label with invalid characters', async () => { + it('should fail when sending label with invalid characters', async () => { await asyncExpectThrowRNSError(() => rns.subdomains.available('domain.rsk', 'iNVA-lid'), INVALID_LABEL); }); }); describe('happy paths', () => { - test('should return false if label is not available', async () => { + it('should return false if label is not available', async () => { const available = await rns.subdomains.available('testing.rsk', 'multichain'); expect(available).toBe(false); }); - test('should return true if label is available', async () => { + it('should return true if label is available', async () => { const available = await rns.subdomains.available('testing.rsk', 'available'); expect(available).toBe(true); }); diff --git a/test/public-nodes/rns.subdomains.setOwnerAndCreate.test.ts b/test/public-nodes/subdomains.setOwnerAndCreate.test.ts similarity index 83% rename from test/public-nodes/rns.subdomains.setOwnerAndCreate.test.ts rename to test/public-nodes/subdomains.setOwnerAndCreate.test.ts index 962c10b..3ee311d 100644 --- a/test/public-nodes/rns.subdomains.setOwnerAndCreate.test.ts +++ b/test/public-nodes/subdomains.setOwnerAndCreate.test.ts @@ -10,7 +10,7 @@ describe.each([ new Rsk3(PUBLIC_NODE_MAINNET), new Rsk3(PUBLIC_NODE_TESTNET), ])('subdomains', (blockchainApiInstance) => { - test('subdomains.setOwner should fail when web3 instance does not contain accounts to sign the tx', async () => { + it('subdomains.setOwner should fail when web3 instance does not contain accounts to sign the tx', async () => { const rns = new RNS(blockchainApiInstance); await asyncExpectThrowRNSError( () => rns.subdomains.setOwner('multichain.testing.rsk', 'check', '0x0000000000000000000000000000000000000001'), @@ -18,7 +18,7 @@ describe.each([ ); }); - test('subdomains.create should fail when web3 instance does not contain accounts to sign the tx', async () => { + it('subdomains.create should fail when web3 instance does not contain accounts to sign the tx', async () => { const rns = new RNS(blockchainApiInstance); await asyncExpectThrowRNSError( () => rns.subdomains.create('multichain.testing.rsk', 'check'), diff --git a/test/utils.ts b/test/utils.ts index 9a2dd25..f72256a 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -15,30 +15,24 @@ const asyncTryCatchAssert = async (prom: any, assertion: (error: any) => void) = } }; -export const asyncExpectThrowRNSError = async ( +export const asyncExpectThrowRNSError = ( prom: any, expectedError: string, expectedLang = Lang.en, -) => { - await asyncTryCatchAssert( - prom, - (error) => expect(error).toEqual(new RNSError(expectedError, expectedLang)), - ); -}; +) => asyncTryCatchAssert( + prom, + (error) => expect(error).toEqual(new RNSError(expectedError, expectedLang)), +); -export const asyncExpectThrowVMRevert = async (prom: any) => { - await asyncTryCatchAssert( - prom, - (error) => expect(error.message).toContain('VM Exception while processing transaction: revert'), - ); -}; +export const asyncExpectThrowVMRevert = (prom: any) => asyncTryCatchAssert( + prom, + (error) => expect(error.message).toContain('VM Exception while processing transaction: revert'), +); -export const asyncExpectThrowError = async (prom: any) => { - await asyncTryCatchAssert( - prom, - (error) => expect(error).toBeInstanceOf(Error), - ); -}; +export const asyncExpectThrowError = (prom: any) => asyncTryCatchAssert( + prom, + (error) => expect(error).toBeInstanceOf(Error), +); export const expectThrowRNSError = (fn: any, expectedError: string) => { let error; From 174ba058f0660079815b4effbe11f4ad5ea95890 Mon Sep 17 00:00:00 2001 From: Javier Esses Date: Wed, 10 Jun 2020 21:49:46 -0300 Subject: [PATCH 3/3] Return txHash instead of txReceipt (#101) --- src/composer.ts | 14 +-- src/errors/errors.json | 2 +- src/index.ts | 24 +++-- src/resolutions.ts | 141 +------------------------ src/subdomains.ts | 19 +--- src/types/resolutions.ts | 9 +- src/types/rns.ts | 7 +- src/types/subdomains.ts | 5 +- test/local/setAddr.test.ts | 16 +-- test/local/setChainAddr.test.ts | 16 +-- test/local/setResolver.test.ts | 18 ++-- test/local/setReverse.test.ts | 12 +-- test/local/subdomains.create.test.ts | 16 ++- test/local/subdomains.setOwner.test.ts | 16 +-- 14 files changed, 84 insertions(+), 231 deletions(-) diff --git a/src/composer.ts b/src/composer.ts index 81160c6..5f894a8 100644 --- a/src/composer.ts +++ b/src/composer.ts @@ -1,5 +1,4 @@ import Web3 from 'web3'; -import { TransactionReceipt } from 'web3-eth'; import { Composable, Options, ContractAddresses, Contracts, } from './types'; @@ -20,15 +19,6 @@ export default abstract class extends ErrorWrapper implements Composable { public blockchainApi: Web3; - /** - * Create RNS library. - * - * @remarks - * If the blockchain api points to RSK Mainnet or RSK Testnet, no options are required. Contract addresses are detected automatically. - * - * @param blockchainApi - Web3 or Rsk3 instance - * @param options - Overrides network defaults. Optional on RSK Mainnet and RSK Testnet, required for other networks. - */ constructor(blockchainApi: Web3 | any, options?: Options) { super(options && options.lang); @@ -72,7 +62,7 @@ export default abstract class extends ErrorWrapper implements Composable { protected async estimateGasAndSendTransaction( contractMethod: any, customOptions?: TransactionOptions, - ): Promise { + ): Promise { let options: any; if (customOptions && customOptions.from) { @@ -117,7 +107,7 @@ export default abstract class extends ErrorWrapper implements Composable { } return new Promise((resolve, reject) => contractMethod.send(options) - .on('confirmation', (confirmations: Number, receipt: TransactionReceipt) => resolve(receipt)) + .on('transactionHash', (hash: string) => resolve(hash)) .on('error', reject)); } diff --git a/src/errors/errors.json b/src/errors/errors.json index 1b6d54d..9801d45 100644 --- a/src/errors/errors.json +++ b/src/errors/errors.json @@ -312,7 +312,7 @@ } }, "NO_CONTENTHASH_INTERFACE": { - "id": "KB026", + "id": "KB027", "message": { "en": "No contenthash interface", "es": "", diff --git a/src/index.ts b/src/index.ts index 5cde2b2..e18b8c9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ import Web3 from 'web3'; -import { TransactionReceipt } from 'web3-eth'; import { RNS, Contracts, Options, ChainId, Utils, Resolutions as IResolutions, @@ -91,11 +90,11 @@ export default class extends Composer implements RNS { * @param chainId - Should match one of the listed in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) * @param options - Custom configs to be used when submitting the transaction * - * @returns TransactionReceipt of the submitted tx + * @returns Transaction hash */ setAddr( domain: string, addr: string, chainId?: ChainId, options?: TransactionOptions, - ): Promise { + ): Promise { if (!chainId) { return this._resolutions.setAddr(domain, addr, options); } @@ -106,6 +105,11 @@ export default class extends Composer implements RNS { /** * Get decoded contenthash of a given domain. * + * @throws NO_RESOLVER when the domain doesn't have resolver - KB003. + * @throws NO_CONTENTHASH_INTERFACE if has an invalid resolver - KB025. + * @throws NO_CONTENTHASH_SET it there is not contenthash resolution set - KB026. + * @throws UNSUPPORTED_CONTENTHASH_PROTOCOL if the contenthash could not be decoded - KB027. + * * @param domain - Domain to be resolved * * @returns @@ -118,10 +122,14 @@ export default class extends Composer implements RNS { /** * Set contenthash of a given domain. * + * @throws NO_ACCOUNTS_TO_SIGN if the given blockchain api instance does not have associated accounts to sign the transaction - KB015 + * @throws NO_RESOLVER when the domain doesn't have resolver - KB003. + * @throws UNSUPPORTED_CONTENTHASH_PROTOCOL if the contenthash could not be encoded - KB027. + * * @param domain - Domain to be resolved * @param content - Content to be associated to the given domain. Must be decoded, the library will encode and save it. * - * @returns TransactionReceipt of the submitted tx + * @returns Transaction hash */ setContenthash(domain: string, content: string, options?: TransactionOptions): any { return this._resolutions.setContenthash(domain, content, options); @@ -139,11 +147,11 @@ export default class extends Composer implements RNS { * @param resolver - Address to be set as the resolver of the given domain * @param options - Custom configs to be used when submitting the transaction * - * @returns TransactionReceipt of the submitted tx + * @returns Transaction hash */ setResolver( domain: string, resolver: string, options?: TransactionOptions, - ): Promise { + ): Promise { return this._resolutions.setResolver(domain, resolver, options); } @@ -172,9 +180,9 @@ export default class extends Composer implements RNS { * @throws NO_REVERSE_REGISTRAR if there is no owner for `addr.reverse` node - KB022 * @throws NO_SET_NAME_METHOD if reverse registrar does not implement `setName` method - KB023 * - * @returns TransactionReceipt of the submitted tx + * @returns Transaction hash */ - setReverse(name: string, options?: TransactionOptions): Promise { + setReverse(name: string, options?: TransactionOptions): Promise { return this._resolutions.setName(name, options); } diff --git a/src/resolutions.ts b/src/resolutions.ts index f5e1ff6..0b2b171 100644 --- a/src/resolutions.ts +++ b/src/resolutions.ts @@ -1,6 +1,5 @@ import Web3 from 'web3'; import { Contract } from 'web3-eth-contract'; -import { TransactionReceipt } from 'web3-eth'; import { formatsByCoinType } from '@ensdomains/address-encoder'; import { createAddrResolver, createChainAddrResolver, createNameResolver, @@ -31,34 +30,14 @@ import { CoinType } from './types/enums'; import ContenthashHelper from './contenthash-helper'; import { DecodedContenthash } from './types/resolutions'; -/** - * Standard resolution protocols. - */ export default class extends Composer implements Resolutions { _contenthashHelper: ContenthashHelper; - /** - * - * @param blockchainApi - current Web3 or Rsk3 instance - * @param options - Overrides network defaults. Optional on RSK Mainnet and RSK Testnet, required for other networks. - */ constructor(public blockchainApi: Web3 | any, options?: Options) { super(blockchainApi, options); this._contenthashHelper = new ContenthashHelper(options); } - /** - * Instance the resolver associated with the given node and checks if is valid according to the given interface. - * - * @throws provided `errorMessage` if the resolver is not ERC165 or it doesn't implement the necessary given interface. - * @throws `noResolverError` || NO_RESOLVER when the domain doesn't have resolver - KB003. - * - * @param node - namehash of the domain to resolve - * @param methodInterface - standard resolution interface id - * @param errorMessage - error message in case the resolver is not valid - * @param contractFactory - factory function used to instance the resolver - * @param noResolverError - custom error to throw if no resolver found - */ private async _createResolver( node: string, contractFactory: (blockchainApi: Web3 | any, address: string) => Contract, @@ -111,18 +90,6 @@ export default class extends Composer implements Resolutions { } } - /** - * addr resolution protocol. - - * @throws NO_ADDR_RESOLUTION_SET if the resolution hasn't been set yet - KB001. - * @throws NO_ADDR_RESOLUTION it has an invalid resolver - KB002. - * @throws NO_RESOLVER when the domain doesn't have resolver - KB003. - * - * @param domain - Domain to be resolved - * - * @return - * Address resolution for the given domain - */ async addr(domain: string): Promise { await this.compose(); const node: string = namehash(domain); @@ -146,19 +113,6 @@ export default class extends Composer implements Resolutions { return toChecksumAddress(addr, this.currentNetworkId); } - /** - * chainAddr resolution protocol. - * - * @throws NO_CHAIN_ADDR_RESOLUTION_SET if the resolution hasn't been set yet - KB007. - * @throws NO_CHAIN_ADDR_RESOLUTION it has an invalid resolver - KB006. - * @throws NO_RESOLVER when the domain doesn't have resolver - KB003. - * - * @param domain - Domain to be resolved - * @param chainId - chain identifier listed in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) - * - * @return - * Address resolution for a domain in a given chain - */ async chainAddr(domain: string, chainId: ChainId): Promise { await this.compose(); const node: string = namehash(domain); @@ -216,23 +170,9 @@ export default class extends Composer implements Resolutions { return addr; } - /** - * Sets addr for the given domain using the AbstractAddrResolver interface. - * - * @throws NO_SET_ADDR it has an invalid resolver - KB018. - * @throws NO_RESOLVER when the domain doesn't have resolver - KB003. - * @throws NO_ACCOUNTS_TO_SIGN if the given blockchainApi instance does not have associated accounts to sign the transaction - KB015 - * @throws INVALID_ADDRESS if the given addr is invalid - KB017 - * @throws INVALID_CHECKSUM_ADDRESS if the given addr has an invalid checksum - KB019 - * - * @param domain - Domain to set resolution - * @param addr - Address to be set as the resolution of the given domain - * @param options - Custom configs to be used when submitting the transaction - * - */ async setAddr( domain: string, addr: string, options?: TransactionOptions, - ): Promise { + ): Promise { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { @@ -250,25 +190,9 @@ export default class extends Composer implements Resolutions { return this.estimateGasAndSendTransaction(contractMethod, options); } - /** - * Sets addr for the given domain using the AbstractAddrResolver interface. - * - * @throws NO_SET_CHAIN_ADDR if it has an invalid resolver - KB024. - * @throws NO_RESOLVER when the domain doesn't have resolver - KB003. - * @throws NO_ACCOUNTS_TO_SIGN if the given blockchain api instance does not have associated accounts to sign the transaction - KB015 - * @throws INVALID_ADDRESS if the given addr is invalid when the chainId belongs to an EVM compatible blockchain - KB017 - * @throws INVALID_CHECKSUM_ADDRESS if the given addr has an invalid checksum and the chainId belongs to an EVM compatible blockchain - KB019 - * - * @param domain - Domain to set resolution - * @param addr - Address to be set as the resolution of the given domain - * @param chainId - chain identifier listed in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) - * @param options - Custom configs to be used when submitting the transaction - * - * - */ async setChainAddr( domain: string, addr: string, chainId: ChainId, options?: TransactionOptions, - ): Promise { + ): Promise { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { @@ -307,14 +231,6 @@ export default class extends Composer implements Resolutions { return this.estimateGasAndSendTransaction(contractMethod, options); } - /** - * Get decoded contenthash of a given domain. - * - * @param domain - Domain to be resolved - * - * @return - * Decoded contenthash associated to the given domain - */ async contenthash(domain: string): Promise { await this.compose(); const node: string = namehash(domain); @@ -344,18 +260,9 @@ export default class extends Composer implements Resolutions { return decoded!; } - /** - * Set contenthash of a given domain. - * - * @param domain - Domain to be resolved - * @param content - Content to be associated to the given domain. Must be decoded, the library will encode and save it. - * - * @return - * TransactionReceipt of the submitted tx - */ async setContenthash( domain: string, content: string, options?: TransactionOptions, - ): Promise { + ): Promise { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { @@ -373,22 +280,9 @@ export default class extends Composer implements Resolutions { return this.estimateGasAndSendTransaction(contractMethod, options); } - /** - * Set resolver of a given domain. - * - * @throws NO_ACCOUNTS_TO_SIGN if the given blockchain api instance does not have associated accounts to sign the transaction - KB015 - * @throws INVALID_ADDRESS if the given resolver address is invalid - KB017 - * @throws INVALID_CHECKSUM_ADDRESS if the given resolver address has an invalid checksum - KB019 - * @throws DOMAIN_NOT_EXISTS if the given domain does not exists - KB012 - * - * @param domain - Domain to set resolver - * @param resolver - Address to be set as the resolver of the given domain - * @param options - Custom configs to be used when submitting the transaction - * - */ async setResolver( domain: string, resolver: string, options?: TransactionOptions, - ): Promise { + ): Promise { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { @@ -409,21 +303,7 @@ export default class extends Composer implements Resolutions { return this.estimateGasAndSendTransaction(contractMethod, options); } - /** - * Set reverse resolution with the given name for the current address - * - * @throws NO_ACCOUNTS_TO_SIGN if the given blockchain api instance does not have associated accounts to sign the transaction - KB015 - * @throws INVALID_DOMAIN if the given domain is empty, is not alphanumeric or if has uppercase characters - KB010 - * @throws NO_REVERSE_REGISTRAR if there is no owner for `addr.reverse` node - KB022 - * @throws NO_SET_NAME_METHOD if reverse registrar does not implement `setName` method - KB023 - * - * @param name - Domain to set resolver - * @param resolver - Address to be set as the resolver of the given domain - * @param options - Custom configs to be used when submitting the transaction - * - * @returns TransactionReceipt of the submitted tx - */ - async setName(name: string, options?: TransactionOptions): Promise { + async setName(name: string, options?: TransactionOptions): Promise { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { @@ -457,17 +337,6 @@ export default class extends Composer implements Resolutions { return this.estimateGasAndSendTransaction(contractMethod, options); } - /** - * name resolution protocol. - * - * @throws NO_REVERSE_RESOLUTION_SET when the domain has not the reverse resolution set - KB014. - * @throws NO_NAME_RESOLUTION if has an invalid name resolver - KB013. - * - * @param address - address to be resolved - * - * @return - * Domain or subdomain associated to the given address. - */ async name(address: string): Promise { await this.compose(); const convertedAddress = address.substring(2).toLowerCase(); // remove '0x' diff --git a/src/subdomains.ts b/src/subdomains.ts index 86af55d..0088a0b 100644 --- a/src/subdomains.ts +++ b/src/subdomains.ts @@ -1,5 +1,4 @@ import Web3 from 'web3'; -import { TransactionReceipt } from 'web3-eth'; import { Subdomains, Options, Resolutions } from './types'; import { SEARCH_DOMAINS_UNDER_AVAILABLE_TLDS, INVALID_DOMAIN, @@ -16,15 +15,7 @@ import { } from './utils'; import { TransactionOptions } from './types/options'; -/** - * Set of subdomains related methods - */ export default class extends Composer implements Subdomains { - /** - * - * @param blockchainApi - current Web3 or Rsk3 instance - * @param registry - RNS registry used to look for given domains - */ constructor(blockchainApi: Web3 | any, private _resolutions: Resolutions, options?: Options) { super(blockchainApi, options); } @@ -34,7 +25,7 @@ export default class extends Composer implements Subdomains { label: string, owner: string, options?: TransactionOptions, - ): Promise { + ): Promise { const contractMethod = this._contracts.registry .methods .setSubnodeOwner( @@ -114,11 +105,11 @@ export default class extends Composer implements Subdomains { * @param owner - The owner of the new subdomain * @param options - Custom configs to be used when submitting the transaction * - * @returns Transaction receipt + * @returns Transaction hash */ async setOwner( domain: string, label: string, owner: string, options?: TransactionOptions, - ): Promise { + ): Promise { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { @@ -158,7 +149,7 @@ export default class extends Composer implements Subdomains { * @param addr - The address to be set as resolution of the new subdomain * @param options - Custom configs to be used when submitting the transaction * - * @returns Transaction receipt + * @returns Transaction hash of the latest transaction */ async create( domain: string, @@ -166,7 +157,7 @@ export default class extends Composer implements Subdomains { owner?: string, addr?: string, options?: TransactionOptions, - ): Promise { + ): Promise { await this.compose(); if (!await hasAccounts(this.blockchainApi)) { diff --git a/src/types/resolutions.ts b/src/types/resolutions.ts index 9b67e83..196d4ea 100644 --- a/src/types/resolutions.ts +++ b/src/types/resolutions.ts @@ -1,4 +1,3 @@ -import { TransactionReceipt } from 'web3-eth'; import { ChainId } from './enums'; import { TransactionOptions } from './options'; @@ -32,7 +31,7 @@ export interface Resolutions { * @param options - Custom configs to be used when submitting the transaction * */ - setAddr(domain: string, addr: string, options?: TransactionOptions): Promise; + setAddr(domain: string, addr: string, options?: TransactionOptions): Promise; /** * Sets addr for the given domain using the AbstractMultiChainResolver interface. @@ -45,7 +44,7 @@ export interface Resolutions { */ setChainAddr( domain: string, addr: string, chainId: ChainId, options?: TransactionOptions - ): Promise; + ): Promise; /** * Get decoded contenthash of a given domain. @@ -72,7 +71,7 @@ export interface Resolutions { */ setResolver( domain: string, resolver: string, options?: TransactionOptions, - ): Promise; + ): Promise; /** * Set reverse resolution with the given name for the current address. @@ -81,7 +80,7 @@ export interface Resolutions { * @param options - Custom configs to be used when submitting the transaction * */ - setName(name: string, options?: TransactionOptions): Promise; + setName(name: string, options?: TransactionOptions): Promise; /** * Reverse lookup: get name of a given address. diff --git a/src/types/rns.ts b/src/types/rns.ts index 5e7fa78..cf06cff 100644 --- a/src/types/rns.ts +++ b/src/types/rns.ts @@ -1,6 +1,5 @@ import { Contract } from 'web3-eth-contract'; import Web3 from 'web3'; -import { TransactionReceipt } from 'web3-eth'; import { ChainId } from './enums'; import { Utils } from './utils'; import { Subdomains } from './subdomains'; @@ -56,7 +55,7 @@ export default interface RNS { */ setAddr( domain: string, addr: string, chainId?: ChainId, options?: TransactionOptions, - ): Promise; + ): Promise; /** * Get decoded contenthash of a given domain. @@ -84,7 +83,7 @@ export default interface RNS { */ setResolver( domain: string, resolver: string, options?: TransactionOptions, - ): Promise; + ): Promise; /** * Set reverse resolution with the given name for the current address. @@ -93,7 +92,7 @@ export default interface RNS { * @param options - Custom configs to be used when submitting the transaction * */ - setReverse(name: string, options?: TransactionOptions): Promise; + setReverse(name: string, options?: TransactionOptions): Promise; /** * Reverse lookup: get name of a given address. diff --git a/src/types/subdomains.ts b/src/types/subdomains.ts index 71eb26b..5a85d85 100644 --- a/src/types/subdomains.ts +++ b/src/types/subdomains.ts @@ -1,4 +1,3 @@ -import { TransactionReceipt } from 'web3-eth'; import { TransactionOptions } from './options'; /** @@ -27,7 +26,7 @@ export interface Subdomains { */ setOwner( domain: string, label: string, owner: string, options?: TransactionOptions, - ): Promise; + ): Promise; /** * Creates a new subdomain under the given domain tree if it is available, and sets its resolution if addr is provided. @@ -42,5 +41,5 @@ export interface Subdomains { */ create( domain: string, label: string, owner?: string, addr?: string, options?: TransactionOptions, - ): Promise; + ): Promise; } diff --git a/test/local/setAddr.test.ts b/test/local/setAddr.test.ts index 8f3275e..5fbbb60 100644 --- a/test/local/setAddr.test.ts +++ b/test/local/setAddr.test.ts @@ -71,12 +71,12 @@ describe.each([ expect(actualAddr).toEqual(ZERO_ADDRESS); }); - it('should return a tx receipt when setting an address', async () => { + it('should return the txHash when setting an address', async () => { await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); const tx = await rns.setAddr('alice.rsk', addr); - expect(tx.transactionHash).toBeTruthy(); + expect(tx).toBeTruthy(); }); it('should set an address when the library is instantiated with a different networkId', async () => { @@ -122,9 +122,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { gasPrice }); + const txHash = await rns.setAddr('alice.rsk', addr, undefined, { gasPrice }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gasPrice).toEqual(gasPrice.toString()); }); @@ -134,9 +134,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { gas }); + const txHash = await rns.setAddr('alice.rsk', addr, undefined, { gas }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gas).toEqual(gas); expect(tx.from).toEqual(defaultSender); @@ -147,9 +147,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), from); - const txReceipt = await rns.setAddr('alice.rsk', addr, undefined, { from }); + const txHash = await rns.setAddr('alice.rsk', addr, undefined, { from }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.from).toEqual(from); }); diff --git a/test/local/setChainAddr.test.ts b/test/local/setChainAddr.test.ts index 6214717..8e1ab49 100644 --- a/test/local/setChainAddr.test.ts +++ b/test/local/setChainAddr.test.ts @@ -92,9 +92,9 @@ describe.each([ it('should return a tx receipt when setting an address', async () => { await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const tx = await rns.setAddr('alice.rsk', rskAddr, ChainId.RSK); + const txHash = await rns.setAddr('alice.rsk', rskAddr, ChainId.RSK); - expect(tx.transactionHash).toBeTruthy(); + expect(txHash).toBeTruthy(); }); it('should throw an error when invalid checksum for RSK', async () => { @@ -126,9 +126,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.setAddr('alice.rsk', btcAddr, ChainId.BITCOIN, { gasPrice }); + const txHash = await rns.setAddr('alice.rsk', btcAddr, ChainId.BITCOIN, { gasPrice }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gasPrice).toEqual(gasPrice.toString()); }); @@ -138,9 +138,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM, { gas }); + const txHash = await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM, { gas }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gas).toEqual(gas); expect(tx.from).toEqual(defaultSender); @@ -151,9 +151,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), from); - const txReceipt = await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM, { from }); + const txHash = await rns.setAddr('alice.rsk', ethAddr, ChainId.ETHEREUM, { from }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.from).toEqual(from); }); diff --git a/test/local/setResolver.test.ts b/test/local/setResolver.test.ts index 1f87ad1..c8e66aa 100644 --- a/test/local/setResolver.test.ts +++ b/test/local/setResolver.test.ts @@ -41,14 +41,14 @@ describe.each([ expect(actualResolver).toBe(addr); }); - it('should return a tx receipt', async () => { + it('should return a tx hash', async () => { const addr = '0x0000000000000000000000000000000001000006'; await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const tx = await rns.setResolver('alice.rsk', addr); + const txHash = await rns.setResolver('alice.rsk', addr); - expect(tx.transactionHash).toBeTruthy(); + expect(txHash).toBeTruthy(); }); it('should throw an error when address is invalid', async () => { @@ -78,9 +78,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.setResolver('alice.rsk', addr, { gasPrice }); + const txHash = await rns.setResolver('alice.rsk', addr, { gasPrice }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gasPrice).toEqual(gasPrice.toString()); }); @@ -90,9 +90,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.setResolver('alice.rsk', addr, { gas }); + const txHash = await rns.setResolver('alice.rsk', addr, { gas }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gas).toEqual(gas); expect(tx.from).toEqual(defaultSender); @@ -103,9 +103,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), from); - const txReceipt = await rns.setResolver('alice.rsk', addr, { from }); + const txHash = await rns.setResolver('alice.rsk', addr, { from }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.from).toEqual(from); }); diff --git a/test/local/setReverse.test.ts b/test/local/setReverse.test.ts index c0f380f..ad0deef 100644 --- a/test/local/setReverse.test.ts +++ b/test/local/setReverse.test.ts @@ -75,9 +75,9 @@ describe.each([ it('should send custom gasPrice', async () => { const gasPrice = '70000000'; - const txReceipt = await rns.setReverse('alice.rsk', { gasPrice }); + const txHash = await rns.setReverse('alice.rsk', { gasPrice }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gasPrice).toEqual(gasPrice.toString()); }); @@ -85,9 +85,9 @@ describe.each([ it('should send custom gas', async () => { const gas = 800000; - const txReceipt = await rns.setReverse('alice.rsk', { gas }); + const txHash = await rns.setReverse('alice.rsk', { gas }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gas).toEqual(gas); expect(tx.from).toEqual(defaultSender); @@ -96,9 +96,9 @@ describe.each([ it('should send custom sender', async () => { const [from] = accounts; - const txReceipt = await rns.setReverse('alice.rsk', { from }); + const txHash = await rns.setReverse('alice.rsk', { from }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.from).toEqual(from); }); diff --git a/test/local/subdomains.create.test.ts b/test/local/subdomains.create.test.ts index 57137f5..dd75e45 100644 --- a/test/local/subdomains.create.test.ts +++ b/test/local/subdomains.create.test.ts @@ -2,7 +2,6 @@ import Web3 from 'web3'; import { accounts, web3, defaultSender } from '@openzeppelin/test-environment'; import { hash as namehash } from 'eth-ens-namehash'; import Rsk3 from '@rsksmart/rsk3'; -import { TransactionReceipt } from 'web3-eth'; import RNS from '../../src/index'; import { Options, NetworkId } from '../../src/types'; import { @@ -146,7 +145,7 @@ describe.each([ const addr = '0x0000000000000000000000000000000001000006'; let expectedAddr: string; let expectedOwner: string; - let tx: TransactionReceipt | null; + let tx: string | null; beforeEach(async () => { await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); @@ -195,7 +194,6 @@ describe.each([ expect(actualAddr).toEqual(expectedAddr); expect(tx).toBeTruthy(); - expect(tx?.transactionHash).toBeTruthy(); tx = null; expectedAddr = ''; @@ -211,9 +209,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.subdomains.create('alice.rsk', 'test', owner, addr, { gasPrice }); + const txHash = await rns.subdomains.create('alice.rsk', 'test', owner, addr, { gasPrice }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gasPrice).toEqual(gasPrice.toString()); }); @@ -223,9 +221,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.subdomains.create('alice.rsk', 'test', owner, addr, { gas }); + const txHash = await rns.subdomains.create('alice.rsk', 'test', owner, addr, { gas }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gas).toEqual(gas); expect(tx.from).toEqual(defaultSender); @@ -236,9 +234,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), from); - const txReceipt = await rns.subdomains.create('alice.rsk', 'test', owner, addr, { from }); + const txHash = await rns.subdomains.create('alice.rsk', 'test', owner, addr, { from }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.from).toEqual(from); }); diff --git a/test/local/subdomains.setOwner.test.ts b/test/local/subdomains.setOwner.test.ts index 2984246..da06135 100644 --- a/test/local/subdomains.setOwner.test.ts +++ b/test/local/subdomains.setOwner.test.ts @@ -114,9 +114,9 @@ describe.each([ it('should return a tx receipt', async () => { await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const tx = await rns.subdomains.setOwner('alice.rsk', 'test', owner); + const txHash = await rns.subdomains.setOwner('alice.rsk', 'test', owner); - expect(tx.transactionHash).toBeTruthy(); + expect(txHash).toBeTruthy(); }); it('should create a subdomain even if is not available', async () => { @@ -143,9 +143,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.subdomains.setOwner('alice.rsk', 'test', owner, { gasPrice }); + const txHash = await rns.subdomains.setOwner('alice.rsk', 'test', owner, { gasPrice }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gasPrice).toEqual(gasPrice.toString()); }); @@ -155,9 +155,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), defaultSender); - const txReceipt = await rns.subdomains.setOwner('alice.rsk', 'test', owner, { gas }); + const txHash = await rns.subdomains.setOwner('alice.rsk', 'test', owner, { gas }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.gas).toEqual(gas); expect(tx.from).toEqual(defaultSender); @@ -168,9 +168,9 @@ describe.each([ await registry.setSubnodeOwner(namehash('rsk'), labelhash('alice'), from); - const txReceipt = await rns.subdomains.setOwner('alice.rsk', 'test', owner, { from }); + const txHash = await rns.subdomains.setOwner('alice.rsk', 'test', owner, { from }); - const tx = await web3.eth.getTransaction(txReceipt.transactionHash); + const tx = await web3.eth.getTransaction(txHash); expect(tx.from).toEqual(from); });