Skip to content

Commit

Permalink
chore: add generics to 2fa fetchers
Browse files Browse the repository at this point in the history
  • Loading branch information
simonheys committed Mar 31, 2023
1 parent 409678a commit ee03b76
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 91 deletions.
22 changes: 18 additions & 4 deletions packages/extension/src/shared/api/fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/** generic json fetcher */

export type Fetcher = (
import { useAppState } from "../../ui/app.state"

export type Fetcher = <T>(
input: RequestInfo | URL,
init?: RequestInit,
) => Promise<any>
) => Promise<T>

export interface FetcherError extends Error {
url?: string
Expand Down Expand Up @@ -37,7 +39,10 @@ export const fetcherError = (
return error
}

export const fetcher = async (input: RequestInfo | URL, init?: RequestInit) => {
export const fetcher = async <T>(
input: RequestInfo | URL,
init?: RequestInit,
): Promise<T> => {
const response = await fetch(input, init)
/** capture text here in the case of json parse failure we can include it in the error */
const responseText = await response.text()
Expand All @@ -64,7 +69,7 @@ export const fetcherWithArgentApiHeadersForNetwork = (
network: string,
fetcherImpl: Fetcher = fetcher,
) => {
const fetcherWithArgentApiHeaders = (
const fetcherWithArgentApiHeaders: Fetcher = (
input: RequestInfo | URL,
init?: RequestInit,
) => {
Expand All @@ -80,6 +85,15 @@ export const fetcherWithArgentApiHeadersForNetwork = (
return fetcherWithArgentApiHeaders
}

export const fetcherWithArgentApiHeaders = (fetcherImpl: Fetcher = fetcher) => {
const { switcherNetworkId } = useAppState.getState()
const fetcher = fetcherWithArgentApiHeadersForNetwork(
switcherNetworkId,
fetcherImpl,
)
return fetcher
}

/** convert KnownNetworksType to 'goerli' or 'mainnet' expected by API */

export const argentApiNetworkForNetwork = (network: string) => {
Expand Down
116 changes: 68 additions & 48 deletions packages/extension/src/shared/shield/backend/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import {
Cosigner,
CosignerMessage,
CosignerOffchainMessage,
CosignerResponse,
} from "@argent/guardian"
import retry from "async-retry"
import urlJoin from "url-join"
import { z } from "zod"

import { ARGENT_API_BASE_URL } from "../../api/constants"
Expand All @@ -18,7 +20,7 @@ export const requestEmailAuthentication = async (
) => {
try {
const json = await jwtFetcher(
`${ARGENT_API_BASE_URL}/account/requestEmailAuthentication`,
urlJoin(ARGENT_API_BASE_URL, `account/requestEmailAuthentication`),
{
method: "POST",
body: JSON.stringify({
Expand All @@ -42,7 +44,7 @@ const emailVerificationStatus = [
"notRequested",
] as const

export type EmailVerificationStatus = (typeof emailVerificationStatus)[number]
export type EmailVerificationStatus = typeof emailVerificationStatus[number]

export const emailVerificationStatusErrorSchema = z.object({
name: z.string(),
Expand All @@ -55,17 +57,20 @@ export const emailVerificationStatusErrorSchema = z.object({
}),
})

export const getEmailVerificationStatus =
async (): Promise<EmailVerificationStatus> => {
try {
const json = await jwtFetcher(
`${ARGENT_API_BASE_URL}/account/emailVerificationStatus`,
)
return json.status
} catch (error) {
throw new Error("Failed to get email verification status")
}
export interface GetEmailVerificationStatusReponse {
status: EmailVerificationStatus
}

export const getEmailVerificationStatus = async () => {
try {
const json = await jwtFetcher<GetEmailVerificationStatusReponse>(
urlJoin(ARGENT_API_BASE_URL, `account/emailVerificationStatus`),
)
return json.status
} catch (error) {
throw new Error("Failed to get email verification status")
}
}

export const getVerificationErrorMessage = (
status: EmailVerificationStatus,
Expand All @@ -84,10 +89,10 @@ export const getVerificationErrorMessage = (
}
}

export const register = async (): Promise<void> => {
export const register = async () => {
try {
const json = await jwtFetcher(
`${ARGENT_API_BASE_URL}/account/asyncRegister`,
const json = await jwtFetcher<void>(
urlJoin(ARGENT_API_BASE_URL, `account/asyncRegister`),
{
method: "POST",
body: JSON.stringify({}),
Expand Down Expand Up @@ -125,11 +130,9 @@ interface VerifyEmailResponse {
userRegistrationStatus: "registered" | "notRegistered"
}

export const verifyEmail = async (
verificationCode: string,
): Promise<VerifyEmailResponse> => {
const json: VerifyEmailResponse = await jwtFetcher(
`${ARGENT_API_BASE_URL}/verifyEmail`,
export const verifyEmail = async (verificationCode: string) => {
const json = await jwtFetcher<VerifyEmailResponse>(
urlJoin(ARGENT_API_BASE_URL, `verifyEmail`),
{
method: "POST",
body: JSON.stringify({
Expand All @@ -142,10 +145,14 @@ export const verifyEmail = async (

type RegistrationStatus = "notFound" | "registering" | "registered" | "failed"

export const getRegistrationStatus = async (): Promise<RegistrationStatus> => {
interface GetRegistrationStatusResponse {
status: RegistrationStatus
}

export const getRegistrationStatus = async () => {
try {
const json = await jwtFetcher(
`${ARGENT_API_BASE_URL}/account/registrationStatus`,
const json = await jwtFetcher<GetRegistrationStatusResponse>(
urlJoin(ARGENT_API_BASE_URL, `account/registrationStatus`),
)
return json.status
} catch (error) {
Expand All @@ -155,7 +162,7 @@ export const getRegistrationStatus = async (): Promise<RegistrationStatus> => {

export const isTokenExpired = async () => {
try {
await jwtFetcher(`${ARGENT_API_BASE_URL}/account`)
await jwtFetcher<void>(urlJoin(ARGENT_API_BASE_URL, `account`))
return false
} catch (error) {
IS_DEV && console.warn(coerceErrorToString(error))
Expand All @@ -176,10 +183,17 @@ export interface BackendAccount {
salt: string | null
}

export const getBackendAccounts = async (): Promise<BackendAccount[]> => {
interface GetAccountsResponse {
accounts: BackendAccount[]
}

export const getBackendAccounts = async () => {
try {
const json = await jwtFetcher(
`${ARGENT_API_BASE_URL}/accounts?application=argentx&chain=starknet`,
const json = await jwtFetcher<GetAccountsResponse>(
urlJoin(
ARGENT_API_BASE_URL,
`accounts?application=argentx&chain=starknet`,
),
)
return json.accounts
} catch (error) {
Expand All @@ -196,22 +210,25 @@ export const addBackendAccount = async (
pubKey: string,
accountAddress: string,
signature: string[],
): Promise<AddAccountResponse> => {
) => {
try {
const json = await jwtFetcher(`${ARGENT_API_BASE_URL}/account`, {
method: "POST",
body: JSON.stringify({
chain: "starknet",
application: "argentx",
ownerAddress: pubKey,
accountAddress,
signature: {
r: signature[0],
s: signature[1],
},
assignCosigner: true,
}),
})
const json = await jwtFetcher<AddAccountResponse>(
urlJoin(ARGENT_API_BASE_URL, `account`),
{
method: "POST",
body: JSON.stringify({
chain: "starknet",
application: "argentx",
ownerAddress: pubKey,
accountAddress,
signature: {
r: signature[0],
s: signature[1],
},
assignCosigner: true,
}),
},
)
return json
} catch (error) {
throw new Error("Failed to add account")
Expand All @@ -223,14 +240,17 @@ export const cosignerSign: Cosigner = async (
isOffchainMessage = false,
) => {
const beEndpoint = isOffchainMessage
? "/cosigner/personalSign"
: `/cosigner/sign`
? "cosigner/personalSign"
: `cosigner/sign`

try {
const json = await jwtFetcher(`${ARGENT_API_BASE_URL}${beEndpoint}`, {
method: "POST",
body: JSON.stringify(message),
})
const json = await jwtFetcher<CosignerResponse>(
urlJoin(ARGENT_API_BASE_URL, beEndpoint),
{
method: "POST",
body: JSON.stringify(message),
},
)
return json
} catch (error) {
if (isFetcherError(error) && error.responseJson?.status) {
Expand Down
10 changes: 4 additions & 6 deletions packages/extension/src/shared/shield/jwtFetcher.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { useAppState } from "../../ui/app.state"
import { fetcherWithArgentApiHeadersForNetwork } from "../api/fetcher"
import { fetcherWithArgentApiHeaders } from "../api/fetcher"
import { IS_DEV } from "../utils/dev"
import { coerceErrorToString } from "../utils/error"
import { generateJwt } from "./jwt"

/** wraps fetcher, generates and uses bearer jwt */

export const jwtFetcher = async (
export const jwtFetcher = async <T>(
input: RequestInfo | URL,
init?: RequestInit,
) => {
Expand All @@ -19,10 +18,9 @@ export const jwtFetcher = async (
"Content-Type": "application/json",
},
}
const { switcherNetworkId } = useAppState.getState()
const fetcher = fetcherWithArgentApiHeadersForNetwork(switcherNetworkId)
const fetcher = fetcherWithArgentApiHeaders()
try {
return fetcher(input, initWithArgentJwtHeaders)
return fetcher<T>(input, initWithArgentJwtHeaders)
} catch (error) {
IS_DEV && console.warn(coerceErrorToString(error))
throw error
Expand Down
19 changes: 11 additions & 8 deletions packages/extension/src/shared/transactionReview.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const apiTransactionReviewActivityType = [
] as const

export type ApiTransactionReviewActivityType =
(typeof apiTransactionReviewActivityType)[number]
typeof apiTransactionReviewActivityType[number]

export type TransactionReviewWithType = ApiTransactionReview & {
type: ApiTransactionReviewActivityType
Expand Down Expand Up @@ -145,14 +145,17 @@ export const fetchTransactionReview = ({
account: accountAddress,
calls,
}
return fetcherImpl(ARGENT_TRANSACTION_REVIEW_STARKNET_URL, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
return fetcherImpl<ApiTransactionReviewResponse>(
ARGENT_TRANSACTION_REVIEW_STARKNET_URL,
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(body),
},
body: JSON.stringify(body),
})
)
}

export const getDisplayWarnAndReasonForTransactionReview = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { ARGENT_TRANSACTION_SIMULATION_URL } from "../api/constants"
import { fetcher } from "../api/fetcher"
import { sendMessage, waitForMessage } from "../messages"
import { findTransfersAndApprovals } from "./findTransferAndApproval"
import type {
import {
ApiTransactionSimulationResponse,
IFetchTransactionSimulation,
TransactionSimulationApproval,
TransactionSimulationTransfer,
Expand Down Expand Up @@ -35,20 +36,21 @@ export const fetchTransactionSimulation = async ({
try {
const { invocation, chainId } = data

const backendSimulation = await fetcherImpl(
ARGENT_TRANSACTION_SIMULATION_URL,
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
const backendSimulation =
await fetcherImpl<ApiTransactionSimulationResponse>(
ARGENT_TRANSACTION_SIMULATION_URL,
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
...invocation,
chainId,
}),
},
body: JSON.stringify({
...invocation,
chainId,
}),
},
)
)
return backendSimulation
} catch (e) {
console.error("Failed to fetch transaction simulation from backend", e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import {
settingsStore,
} from "../../../../shared/settings"
import { useKeyValueStorage } from "../../../../shared/storage/hooks"
import {
ApiTransactionReviewResponse,
fetchTransactionReview,
} from "../../../../shared/transactionReview.service"
import { fetchTransactionReview } from "../../../../shared/transactionReview.service"
import { argentApiFetcher } from "../../../services/argentApiFetcher"
import { useConditionallyEnabledSWR } from "../../../services/swr"
import { Account } from "../../accounts/Account"
Expand Down Expand Up @@ -59,7 +56,7 @@ export const useTransactionReview = ({
})
// TODO: come back - dont rerender when fetcher reference changes
}, [account, transactions]) // eslint-disable-line react-hooks/exhaustive-deps
return useConditionallyEnabledSWR<ApiTransactionReviewResponse>(
return useConditionallyEnabledSWR(
Boolean(transactionReviewEnabled),
[actionHash, "transactionReview"],
transactionReviewFetcher,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
} from "../../../../shared/settings"
import { useKeyValueStorage } from "../../../../shared/storage/hooks"
import { fetchTransactionSimulation } from "../../../../shared/transactionSimulation/transactionSimulation.service"
import { ApiTransactionSimulationResponse } from "../../../../shared/transactionSimulation/types"
import { argentApiFetcher } from "../../../services/argentApiFetcher"
import { useConditionallyEnabledSWR } from "../../../services/swr"
import { Account } from "../../accounts/Account"
Expand Down Expand Up @@ -50,7 +49,7 @@ export const useTransactionSimulation = ({
fetcher: argentApiFetcher,
})
}, [account, transactions]) // eslint-disable-line react-hooks/exhaustive-deps
return useConditionallyEnabledSWR<ApiTransactionSimulationResponse>(
return useConditionallyEnabledSWR(
Boolean(transactionSimulationEnabled),
[actionHash, "transactionSimulation"],
transactionSimulationFetcher,
Expand Down
Loading

0 comments on commit ee03b76

Please sign in to comment.