Skip to content

Commit

Permalink
fix(dcd): refactor and pull useSubmit hook apart
Browse files Browse the repository at this point in the history
  • Loading branch information
dominik-stumpf committed Jul 26, 2024
1 parent a18a165 commit ac73283
Show file tree
Hide file tree
Showing 14 changed files with 130 additions and 127 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import useGuild from "components/[guild]/hooks/useGuild"
import useShowErrorToast from "hooks/useShowErrorToast"
import { SignedValidation, useSubmitWithSign } from "hooks/useSubmit"
import { UseSubmitOptions } from "hooks/useSubmit/useSubmit"
import { UseSubmitOptions } from "hooks/useSubmit/types"
import useToast from "hooks/useToast"
import fetcher from "utils/fetcher"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { AccessCheckJob, JoinJob } from "@guildxyz/types"
import useGuild from "components/[guild]/hooks/useGuild"
import useMembership from "components/explorer/hooks/useMembership"
import { useFetcherWithSign } from "hooks/useFetcherWithSign"
import { UseSubmitOptions } from "hooks/useSubmit/useSubmit"
import { UseSubmitOptions } from "hooks/useSubmit/types"
import { atom, useAtom } from "jotai"
import useSWRImmutable from "swr/immutable"
import { groupBy } from "../utils/mapAccessJobState"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { env } from "env"
import { useFetcherWithSign } from "hooks/useFetcherWithSign"
import usePopupWindow from "hooks/usePopupWindow"
import useSubmit, { SignedValidation, useSubmitWithSign } from "hooks/useSubmit"
import { UseSubmitOptions } from "hooks/useSubmit/useSubmit"
import { UseSubmitOptions } from "hooks/useSubmit/types"
import { useSetAtom } from "jotai"
import { OAuthResultParams } from "pages/oauth-result"
import { useCallback, useMemo } from "react"
Expand Down
2 changes: 1 addition & 1 deletion src/components/[guild]/JoinModal/hooks/useJoin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { GUILD_PIN_MAINTENANCE } from "components/[guild]/Requirements/component
import { useMintGuildPinContext } from "components/[guild]/Requirements/components/GuildCheckout/MintGuildPinContext"
import useGuild from "components/[guild]/hooks/useGuild"
import useUser from "components/[guild]/hooks/useUser"
import { UseSubmitOptions } from "hooks/useSubmit/useSubmit"
import { UseSubmitOptions } from "hooks/useSubmit/types"
import { useToastWithButton, useToastWithTweetButton } from "hooks/useToast"
import { useRouter } from "next/router"
import { useState } from "react"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import useMembership from "components/explorer/hooks/useMembership"
import useCustomPosthogEvents from "hooks/useCustomPosthogEvents"
import { useFetcherWithSign } from "hooks/useFetcherWithSign"
import useSubmit from "hooks/useSubmit"
import { UseSubmitOptions } from "hooks/useSubmit/useSubmit"
import { UseSubmitOptions } from "hooks/useSubmit/types"
import { atom, useAtom } from "jotai"
import useUsersPoints from "rewards/Points/useUsersPoints"
import getGuildPlatformsOfRoles from "../utils/getGuildPlatformsOfRoles"
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useSetKeyPair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { StoredKeyPair, setKeyPairToIdb } from "utils/keyPair"
import { recaptchaAtom, shouldUseReCAPTCHAAtom } from "utils/recaptcha"
import { checksumAddress } from "viem"
import useSubmit from "./useSubmit"
import { MessageParams, SignProps, UseSubmitOptions } from "./useSubmit/useSubmit"
import { MessageParams, SignProps, UseSubmitOptions } from "./useSubmit/types"

function getSiweMessage({
addr,
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/useSubmit/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const DEFAULT_MESSAGE = "Please sign this message"
export const DEFAULT_SIGN_LOADING_TEXT = "Check your wallet"
27 changes: 27 additions & 0 deletions src/hooks/useSubmit/fuelSign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ValidationMethod } from "types"
import { DEFAULT_MESSAGE } from "./constants"
import { FuelSignProps, Validation } from "./types"
import { createMessageParams, getMessage, signWithKeyPair } from "./utils"

export const fuelSign = async ({
wallet,
address,
payload,
keyPair,
forcePrompt,
msg = DEFAULT_MESSAGE,
ts,
}: FuelSignProps): Promise<[string, Validation]> => {
const params = createMessageParams(address, ts, msg, payload)
let sig = null

if (!!keyPair && !forcePrompt) {
params.method = ValidationMethod.KEYPAIR
sig = await signWithKeyPair(keyPair, params)
} else {
params.method = ValidationMethod.FUEL
sig = await wallet.signMessage(getMessage(params))
}

return [payload, { params, sig }]
}
2 changes: 1 addition & 1 deletion src/hooks/useSubmit/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { default, sign, useSubmitWithSign } from "./useSubmit"
export type { SignedValidation, Validation } from "./useSubmit"
export type { SignedValidation, Validation } from "./types"
46 changes: 46 additions & 0 deletions src/hooks/useSubmit/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Account } from "fuels"
import { ValidationMethod } from "types"
import { PublicClient, WalletClient } from "viem"

type SignBaseProps = {
address: `0x${string}`
payload: string
chainId?: string
forcePrompt: boolean
keyPair?: CryptoKeyPair
msg?: string
ts?: number
getMessageToSign?: (params: MessageParams) => string
}

export type SignProps = SignBaseProps & {
publicClient: PublicClient
walletClient: WalletClient
}

export type FuelSignProps = SignBaseProps & { wallet: Account }

export type SignedValidation = { signedPayload: string; validation: Validation }

export type Validation = {
params: MessageParams
sig: string
}

export type MessageParams = {
msg: string
addr: string
method: ValidationMethod
chainId?: string
hash?: string
nonce: string
ts: string
}

export type UseSubmitOptions<ResponseType = void> = {
onSuccess?: (response: ResponseType) => void
onError?: (error: any) => void

// Use catefully! If this is set to true, a .onSubmit() call can reject!
allowThrow?: boolean
}
123 changes: 5 additions & 118 deletions src/hooks/useSubmit/useSubmit.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,21 @@
import { useWeb3ConnectionManager } from "@/components/Web3ConnectionManager/hooks/useWeb3ConnectionManager"
import { useUserPublic } from "@/hooks/useUserPublic"
import { useWallet } from "@fuels/react"
import { Account } from "fuels"
import useLocalStorage from "hooks/useLocalStorage"
import useTimeInaccuracy from "hooks/useTimeInaccuracy"
import randomBytes from "randombytes"
import { useCallback, useState } from "react"
import useSWR from "swr"
import { ValidationMethod } from "types"
import {
PublicClient,
UnauthorizedProviderError,
WalletClient,
createPublicClient,
keccak256,
stringToBytes,
trim,
} from "viem"
import { UnauthorizedProviderError, createPublicClient, trim } from "viem"
import { useChainId, usePublicClient, useWalletClient } from "wagmi"
import { wagmiConfig } from "wagmiConfig"
import { Chain, Chains, supportedChains } from "wagmiConfig/chains"
import { DEFAULT_MESSAGE, DEFAULT_SIGN_LOADING_TEXT } from "./constants"
import { fuelSign } from "./fuelSign"
import { SignProps, UseSubmitOptions, Validation } from "./types"
import { createMessageParams, getMessage, signWithKeyPair } from "./utils"
import gnosisSafeSignCallback from "./utils/gnosisSafeSignCallback"

export type UseSubmitOptions<ResponseType = void> = {
onSuccess?: (response: ResponseType) => void
onError?: (error: any) => void

// Use catefully! If this is set to true, a .onSubmit() call can reject!
allowThrow?: boolean
}

type FetcherFunction<ResponseType> = ({
signedPayload,
validation,
Expand Down Expand Up @@ -82,15 +68,6 @@ const useSubmit = <DataType, ResponseType>(
}
}

export type SignedValidation = { signedPayload: string; validation: Validation }

export type Validation = {
params: MessageParams
sig: string
}

const DEFAULT_MESSAGE = "Please sign this message"

const signCallbacks = [
{
domain: "safe.global",
Expand All @@ -99,31 +76,6 @@ const signCallbacks = [
},
]

export type MessageParams = {
msg: string
addr: string
method: ValidationMethod
chainId?: string
hash?: string
nonce: string
ts: string
}

const getMessage = ({
msg,
addr,
method,
chainId,
hash,
nonce,
ts,
}: MessageParams) =>
`${msg}\n\nAddress: ${addr}\nMethod: ${method}${
chainId ? `\nChainId: ${chainId}` : ""
}${hash ? `\nHash: ${hash}` : ""}\nNonce: ${nonce}\nTimestamp: ${ts}`

const DEFAULT_SIGN_LOADING_TEXT = "Check your wallet"

const useSubmitWithSignWithParamKeyPair = <DataType, ResponseType>(
fetch: FetcherFunction<ResponseType>,
{
Expand Down Expand Up @@ -256,71 +208,6 @@ const useSubmitWithSign = <ResponseType>(
})
}

type SignBaseProps = {
address: `0x${string}`
payload: string
chainId?: string
forcePrompt: boolean
keyPair?: CryptoKeyPair
msg?: string
ts?: number
getMessageToSign?: (params: MessageParams) => string
}

export type SignProps = SignBaseProps & {
publicClient: PublicClient
walletClient: WalletClient
}

export type FuelSignProps = SignBaseProps & { wallet: Account }

const createMessageParams = (
address: `0x${string}`,
ts: number,
msg: string,
payload: string
): MessageParams => ({
addr: address.toLowerCase(),
nonce: randomBytes(32).toString("hex"),
ts: ts.toString(),
hash: payload !== "{}" ? keccak256(stringToBytes(payload)) : undefined,
method: null,
msg,
chainId: undefined,
})

const signWithKeyPair = (keyPair: CryptoKeyPair, params: MessageParams) =>
window.crypto.subtle
.sign(
{ name: "ECDSA", hash: "SHA-512" },
keyPair.privateKey,
Buffer.from(getMessage(params))
)
.then((signatureBuffer) => Buffer.from(signatureBuffer).toString("hex"))

export const fuelSign = async ({
wallet,
address,
payload,
keyPair,
forcePrompt,
msg = DEFAULT_MESSAGE,
ts,
}: FuelSignProps): Promise<[string, Validation]> => {
const params = createMessageParams(address, ts, msg, payload)
let sig = null

if (!!keyPair && !forcePrompt) {
params.method = ValidationMethod.KEYPAIR
sig = await signWithKeyPair(keyPair, params)
} else {
params.method = ValidationMethod.FUEL
sig = await wallet.signMessage(getMessage(params))
}

return [payload, { params, sig }]
}

const chainsOfAddressWithDeployedContract = async (
address: `0x${string}`
): Promise<Chain[]> => {
Expand Down
40 changes: 40 additions & 0 deletions src/hooks/useSubmit/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import randomBytes from "randombytes"
import { keccak256, stringToBytes } from "viem"
import { MessageParams } from "./types"

export const signWithKeyPair = (keyPair: CryptoKeyPair, params: MessageParams) =>
window.crypto.subtle
.sign(
{ name: "ECDSA", hash: "SHA-512" },
keyPair.privateKey,
Buffer.from(getMessage(params))
)
.then((signatureBuffer) => Buffer.from(signatureBuffer).toString("hex"))

export const getMessage = ({
msg,
addr,
method,
chainId,
hash,
nonce,
ts,
}: MessageParams) =>
`${msg}\n\nAddress: ${addr}\nMethod: ${method}${
chainId ? `\nChainId: ${chainId}` : ""
}${hash ? `\nHash: ${hash}` : ""}\nNonce: ${nonce}\nTimestamp: ${ts}`

export const createMessageParams = (
address: `0x${string}`,
ts: number,
msg: string,
payload: string
): MessageParams => ({
addr: address.toLowerCase(),
nonce: randomBytes(32).toString("hex"),
ts: ts.toString(),
hash: payload !== "{}" ? keccak256(stringToBytes(payload)) : undefined,
method: null,
msg,
chainId: undefined,
})
3 changes: 2 additions & 1 deletion src/utils/fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { env } from "env"
import { sign } from "hooks/useSubmit"
import { FuelSignProps, SignProps, fuelSign } from "hooks/useSubmit/useSubmit"
import { fuelSign } from "hooks/useSubmit/fuelSign"
import { FuelSignProps, SignProps } from "hooks/useSubmit/types"
import { pushToIntercomSetting } from "./intercom"

const SIG_HEADER_NAME = "x-guild-sig"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AddressLinkParams } from "@/components/Providers/types"
import { useWeb3ConnectionManager } from "@/components/Web3ConnectionManager/hooks/useWeb3ConnectionManager"
import { useUserPublic } from "@/hooks/useUserPublic"
import useSubmit from "hooks/useSubmit"
import { SignProps } from "hooks/useSubmit/useSubmit"
import { SignProps } from "hooks/useSubmit/types"
import { useAtom } from "jotai"
import randomBytes from "randombytes"
import { useEffect } from "react"
Expand Down

0 comments on commit ac73283

Please sign in to comment.