Skip to content

Commit

Permalink
fix: add hiro api key, closes #4518
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranjamie committed Nov 15, 2023
1 parent 35493d5 commit 8c3f3d2
Show file tree
Hide file tree
Showing 22 changed files with 106 additions and 83 deletions.
12 changes: 11 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const avoidWindowOpenMsg = 'Use `openInNewTab` helper';
const avoidFetchMsg = 'Use `axios` instead for consistency with the rest of the project';

module.exports = {
parser: '@typescript-eslint/parser',
Expand Down Expand Up @@ -34,7 +35,11 @@ module.exports = {
ignoreReadBeforeAssign: false,
},
],
'no-restricted-globals': ['error', { name: 'open', message: avoidWindowOpenMsg }],
'no-restricted-globals': [
'error',
{ name: 'open', message: avoidWindowOpenMsg },
{ name: 'fetch', message: avoidFetchMsg },
],
'no-restricted-properties': [
'error',
{
Expand All @@ -52,6 +57,11 @@ module.exports = {
property: 'close',
message: 'Use `closeWindow` utility helper',
},
{
object: 'window',
property: 'fetch',
message: avoidFetchMsg,
},
],
'@typescript-eslint/no-floating-promises': ['warn'],
'@typescript-eslint/no-unnecessary-type-assertion': ['warn'],
Expand Down
44 changes: 44 additions & 0 deletions src/app/common/api/fetch-wrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import axios from 'axios';

import { HIRO_API_KEY } from '@shared/constants';

const leatherHeaders: HeadersInit = {
'x-leather-version': VERSION,
'x-hiro-api-key': HIRO_API_KEY,
};

/**
* @deprecated Use `axios` directly instead
*/
export function wrappedFetch(input: RequestInfo, init: RequestInit = {}) {
const initHeaders = init.headers || {};
// eslint-disable-next-line no-restricted-globals
return fetch(input, {
credentials: 'omit',
...init,
headers: { ...initHeaders, ...leatherHeaders },
});
}

export async function fetchWithTimeout(
input: RequestInfo,
init: RequestInit & { timeout?: number } = {}
) {
const { timeout = 8000, ...options } = init;

const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);

const response = await wrappedFetch(input, {

Check warning on line 32 in src/app/common/api/fetch-wrapper.ts

View workflow job for this annotation

GitHub Actions / lint-eslint

'wrappedFetch' is deprecated. Use `axios` directly instead

Check warning on line 32 in src/app/common/api/fetch-wrapper.ts

View workflow job for this annotation

GitHub Actions / lint-eslint

'wrappedFetch' is deprecated. Use `axios` directly instead
...options,
signal: controller.signal,
});
clearTimeout(id);

return response;
}

axios.interceptors.request.use(config => {
if (config.url?.includes('hiro.so')) config.headers['x-hiro-api-key'] = HIRO_API_KEY;
return config;
});
31 changes: 0 additions & 31 deletions src/app/common/api/wrapped-fetch.ts

This file was deleted.

6 changes: 0 additions & 6 deletions src/app/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
import { toUnicode } from 'punycode';

import { BitcoinNetworkModes, KEBAB_REGEX } from '@shared/constants';
import { logger } from '@shared/logger';
import type { Blockchains } from '@shared/models/blockchain.model';

export function createNullArrayOfLength(length: number) {
Expand Down Expand Up @@ -264,11 +263,6 @@ export function whenStacksChainId(chainId: ChainID) {
return <T>(chainIdMap: WhenStacksChainIdMap<T>): T => chainIdMap[chainId];
}

export function logAndThrow(msg: string, args: any[] = []) {
logger.error(msg, ...args);
throw new Error(msg);
}

export const parseIfValidPunycode = (s: string) => {
try {
return toUnicode(s);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { Inscription } from './inscription';
interface OrdinalsProps {
setIsLoadingMore: (isLoading: boolean) => void;
}

export function Ordinals({ setIsLoadingMore }: OrdinalsProps) {
const query = useGetInscriptionsInfiniteQuery();
const pages = query.data?.pages;
Expand Down
8 changes: 7 additions & 1 deletion src/app/query/bitcoin/bitcoin-client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import axios from 'axios';

import { fetchData } from '../utils';

class Configuration {
Expand Down Expand Up @@ -112,10 +114,14 @@ class TransactionsApi {
constructor(public configuration: Configuration) {}

async getBitcoinTransaction(txid: string) {
return fetch(`${this.configuration.baseUrl}/tx/${txid}`).then(res => res.json());
const resp = await axios.get(`${this.configuration.baseUrl}/tx/${txid}`);
return resp.data;
}

async broadcastTransaction(tx: string) {
// TODO: refactor to use `axios`
// https://github.com/leather-wallet/extension/issues/4521
// eslint-disable-next-line no-restricted-globals
return fetch(`${this.configuration.baseUrl}/tx`, {
method: 'POST',
body: tx,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ export async function sendAcceptedBitcoinContractOfferToProtocolWallet(
acceptedBitcoinContractOffer: string,
counterpartyWalletURL: string
) {
// TODO: refactor to use `axios`
// https://github.com/leather-wallet/extension/issues/4521
// eslint-disable-next-line no-restricted-globals
const response = await fetch(`${counterpartyWalletURL}/offer/accept`, {
method: 'put',
body: JSON.stringify({
Expand Down
12 changes: 5 additions & 7 deletions src/app/query/bitcoin/ordinals/brc20/brc20-tokens.query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useCallback, useEffect } from 'react';

import { useInfiniteQuery } from '@tanstack/react-query';
import axios from 'axios';

import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { createNumArrayOfRange } from '@app/common/utils';
Expand Down Expand Up @@ -36,16 +37,13 @@ interface Brc20TokenTicker {
}

async function fetchTickerData(ticker: string): Promise<Brc20TokenTicker[]> {
const res = await fetch(`https://brc20api.bestinslot.xyz/v1/get_brc20_ticker/${ticker}`);
if (!res.ok) throw new Error('Failed to fetch BRC-20 token ticker data');
return res.json();
const res = await axios.get(`https://brc20api.bestinslot.xyz/v1/get_brc20_ticker/${ticker}`);
return res.data;
}

async function fetchBrc20TokensByAddress(address: string): Promise<Brc20Token[]> {
const res = await fetch(`https://brc20api.bestinslot.xyz/v1/get_brc20_balance/${address}`);

if (!res.ok) throw new Error('Failed to fetch BRC-20 token balances');
const tokensData = await res.json();
const res = await axios.get(`https://brc20api.bestinslot.xyz/v1/get_brc20_balance/${address}`);
const tokensData = res.data;

const tickerPromises = tokensData.map((token: Brc20TokenResponse) => {
return fetchTickerData(token.tick);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

import { QueryPrefixes } from '@app/query/query-prefixes';

async function getInscriptionTextContent(src: string) {
const res = await fetch(src);
if (!res.ok) throw new Error('Failed to fetch ordinal text content');
return res.text();
const res = await axios.get(src, { responseType: 'text' });
return res.data;
}

export function useInscriptionTextContentQuery(contentSrc: string) {
Expand Down
7 changes: 3 additions & 4 deletions src/app/query/bitcoin/ordinals/inscription.query.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

import { HIRO_INSCRIPTIONS_API_URL } from '@shared/constants';
import { Inscription } from '@shared/models/inscription.model';
Expand All @@ -16,10 +17,8 @@ const inscriptionQueryOptions = {
*/
function fetchInscription() {
return async (id: string) => {
const res = await fetch(`${HIRO_INSCRIPTIONS_API_URL}/${id}`);
if (!res.ok) throw new Error('Error retrieving inscription metadata');
const data = await res.json();
return data as Inscription;
const res = await axios.get(`${HIRO_INSCRIPTIONS_API_URL}/${id}`);
return res.data as Inscription;
};
}

Expand Down
7 changes: 3 additions & 4 deletions src/app/query/bitcoin/ordinals/inscriptions-by-param.query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as btc from '@scure/btc-signer';
import { bytesToHex } from '@stacks/common';
import { useQueries, useQuery } from '@tanstack/react-query';
import axios from 'axios';

import { HIRO_INSCRIPTIONS_API_URL } from '@shared/constants';
import { Paginated } from '@shared/models/api-types';
Expand All @@ -13,10 +14,8 @@ type FetchInscriptionResp = Awaited<ReturnType<ReturnType<typeof fetchInscriptio

function fetchInscriptionsByParam() {
return async (param: string) => {
const res = await fetch(`${HIRO_INSCRIPTIONS_API_URL}?${param}`);
if (!res.ok) throw new Error('Error retrieving inscription metadata');
const data = await res.json();
return data as Paginated<Inscription[]>;
const res = await axios.get(`${HIRO_INSCRIPTIONS_API_URL}?${param}`);
return res.data as Paginated<Inscription[]>;
};
}

Expand Down
3 changes: 2 additions & 1 deletion src/app/query/bitcoin/ordinals/inscriptions.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getTaprootAddress } from '@shared/crypto/bitcoin/bitcoin.utils';
import { InscriptionResponseItem } from '@shared/models/inscription.model';
import { ensureArray } from '@shared/utils';

import { wrappedFetch } from '@app/common/api/fetch-wrapper';
import { createNumArrayOfRange } from '@app/common/utils';
import { QueryPrefixes } from '@app/query/query-prefixes';
import { useCurrentAccountNativeSegwitIndexZeroSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
Expand Down Expand Up @@ -41,7 +42,7 @@ async function fetchInscriptions(addresses: string | string[], offset = 0, limit
params.append('limit', limit.toString());
params.append('offset', offset.toString());

const res = await fetch(`${HIRO_INSCRIPTIONS_API_URL}?${params.toString()}`);
const res = await wrappedFetch(`${HIRO_INSCRIPTIONS_API_URL}?${params.toString()}`);
if (!res.ok) throw new Error('Error retrieving inscription metadata');
const data = await res.json();
return data as InscriptionsQueryResponse;
Expand Down
6 changes: 3 additions & 3 deletions src/app/query/bitcoin/stamps/stamps-by-address.query.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

import { AppUseQueryConfig } from '@app/query/query-config';
import { QueryPrefixes } from '@app/query/query-prefixes';
Expand All @@ -16,9 +17,8 @@ export interface Stamp {
}

async function fetchStampsByAddress(address: string): Promise<Stamp[]> {
return fetch(`https://stampchain.io/api/stamps?wallet_address=${address}`).then(res =>
res.json()
);
const resp = await axios.get(`https://stampchain.io/api/stamps?wallet_address=${address}`);
return resp.data;
}

type FetchStampsByAddressResp = Awaited<ReturnType<typeof fetchStampsByAddress>>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

import { CryptoCurrencies } from '@shared/models/currencies.model';

import { logAndThrow } from '@app/common/utils';

import { marketDataQueryOptions } from '../market-data.query';

async function fetchBinanceMarketData(currency: CryptoCurrencies) {
const resp = await fetch(`https://api1.binance.com/api/v3/ticker/price?symbol=${currency}USDT`);
if (!resp.ok) logAndThrow('Cannot load binance data');
return resp.json();
const resp = await axios.get(
`https://api1.binance.com/api/v3/ticker/price?symbol=${currency}USDT`
);
return resp.data;
}

export function selectBinanceUsdPrice(resp: any) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

import { CryptoCurrencies } from '@shared/models/currencies.model';

import { logAndThrow } from '@app/common/utils';

import { marketDataQueryOptions } from '../market-data.query';

const currencyNameMap: Record<CryptoCurrencies, string> = {
Expand All @@ -12,9 +11,8 @@ const currencyNameMap: Record<CryptoCurrencies, string> = {
};

async function fetchCoincapMarketData(currency: CryptoCurrencies) {
const resp = await fetch(`https://api.coincap.io/v2/assets/${currencyNameMap[currency]}`);
if (!resp.ok) logAndThrow('Cannot load coincap data');
return resp.json();
const resp = await axios.get(`https://api.coincap.io/v2/assets/${currencyNameMap[currency]}`);
return resp.data;
}

export function selectCoincapUsdPrice(resp: any) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

import { CryptoCurrencies } from '@shared/models/currencies.model';

import { logAndThrow } from '@app/common/utils';

import { marketDataQueryOptions } from '../market-data.query';

const currencyNameMap: Record<CryptoCurrencies, string> = {
Expand All @@ -12,11 +11,10 @@ const currencyNameMap: Record<CryptoCurrencies, string> = {
};

async function fetchCoingeckoMarketData(currency: CryptoCurrencies) {
const resp = await fetch(
const resp = await axios.get(
`https://api.coingecko.com/api/v3/simple/price?ids=${currencyNameMap[currency]}&vs_currencies=usd`
);
if (!resp.ok) logAndThrow('Cannot load coingecko data');
return resp.json();
return resp.data;
}

export function selectCoingeckoUsdPrice(resp: any) {
Expand Down
3 changes: 2 additions & 1 deletion src/app/query/common/remote-config/remote-config.query.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import get from 'lodash.get';

import { GITHUB_ORG, GITHUB_REPO } from '@shared/constants';
Expand Down Expand Up @@ -76,7 +77,7 @@ const githubWalletConfigRawUrl = `https://raw.githubusercontent.com/${GITHUB_ORG
async function fetchHiroMessages(): Promise<RemoteConfig> {
if ((!BRANCH_NAME && WALLET_ENVIRONMENT !== 'production') || IS_TEST_ENV)
return localConfig as RemoteConfig;
return fetch(githubWalletConfigRawUrl).then(msg => msg.json());
return axios.get(githubWalletConfigRawUrl);
}

function useRemoteConfig() {
Expand Down
4 changes: 2 additions & 2 deletions src/app/query/stacks/fees/fees.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query';

import { StacksTxFeeEstimation } from '@shared/models/fees/stacks-fees.model';

import { fetcher } from '@app/common/api/wrapped-fetch';
import { wrappedFetch } from '@app/common/api/fetch-wrapper';
import { AppUseQueryConfig } from '@app/query/query-config';
import { useCurrentNetworkState } from '@app/store/networks/networks.hooks';

Expand All @@ -11,7 +11,7 @@ import { RateLimiter, useHiroApiRateLimiter } from '../rate-limiter';
function fetchTransactionFeeEstimation(currentNetwork: any, limiter: RateLimiter) {
return async (estimatedLen: number | null, transactionPayload: string) => {
await limiter.removeTokens(1);
const resp = await fetcher(currentNetwork.chain.stacks.url + '/v2/fees/transaction', {
const resp = await wrappedFetch(currentNetwork.chain.stacks.url + '/v2/fees/transaction', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
Expand Down
2 changes: 1 addition & 1 deletion src/app/query/stacks/network/network.query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';

import { fetchWithTimeout } from '@app/common/api/wrapped-fetch';
import { fetchWithTimeout } from '@app/common/api/fetch-wrapper';

import { RateLimiter, useHiroApiRateLimiter } from '../rate-limiter';

Expand Down
Loading

0 comments on commit 8c3f3d2

Please sign in to comment.