Skip to content

Commit

Permalink
Merge pull request #410 from 00labs/account-management
Browse files Browse the repository at this point in the history
Account management
  • Loading branch information
shan-57blocks authored Jan 3, 2025
2 parents b17df71 + 54f443a commit dc79163
Show file tree
Hide file tree
Showing 24 changed files with 676 additions and 618 deletions.
404 changes: 160 additions & 244 deletions packages/huma-shared/src/services/CampaignService.ts

Large diffs are not rendered by default.

318 changes: 243 additions & 75 deletions packages/huma-shared/src/services/IdentityServiceV2.ts

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions packages/huma-shared/src/solana/chain.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { NETWORK_TYPE } from '../utils'

export enum SolanaChainEnum {
SolanaDevnet = 901,
SolanaMainnet = 900,
Expand All @@ -20,6 +22,10 @@ export function isSolanaTestnet(chainId: SolanaChainEnum): boolean {
return chainId !== SolanaChainEnum.SolanaMainnet
}

export function getSolanaNetworkType(chainId: SolanaChainEnum): NETWORK_TYPE {
return isSolanaTestnet(chainId) ? NETWORK_TYPE.testnet : NETWORK_TYPE.mainnet
}

export function getSolanaExplorerUrl(
chainId: SolanaChainEnum,
signature: string,
Expand Down
15 changes: 12 additions & 3 deletions packages/huma-shared/src/utils/chain.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { AddEthereumChainParameter } from '@web3-react/types'
import { ethers } from 'ethers'

export enum NETWORK_TYPE {
testnet = 'testnet',
mainnet = 'mainnet',
}

export enum CHAIN_TYPE {
EVM = 'evm',
SOLANA = 'solana',
Expand Down Expand Up @@ -178,6 +183,10 @@ export function isTestnet(chainId: number): boolean {
return CHAINS[chainId].isTestnet ?? false
}

export function getEvmNetworkType(chainId: ChainEnum): NETWORK_TYPE {
return isTestnet(chainId) ? NETWORK_TYPE.testnet : NETWORK_TYPE.mainnet
}

export function isChainEnum(
chainId: number | string | undefined,
): chainId is keyof typeof ChainEnum {
Expand All @@ -187,7 +196,7 @@ export function isChainEnum(
function isExtendedChainInformation(
chainInformation: BasicChainInformation | ExtendedChainInformation,
): chainInformation is ExtendedChainInformation {
return !!(chainInformation as ExtendedChainInformation).nativeCurrency
return !!(chainInformation as ExtendedChainInformation)?.nativeCurrency
}

export function getAddChainParameters(
Expand Down Expand Up @@ -217,12 +226,12 @@ export const URLS: { [chainId: number]: string[] } = Object.keys(
return accumulator
}, {})

export const getWalletAddressAbbr = (address: string) => {
export const getWalletAddressAbbr = (address: string, startNum = 6) => {
if (!address) {
return address
}
const { length } = address
return `${address.slice(0, 6)}...${address.slice(length - 4, length)}`
return `${address.slice(0, startNum)}...${address.slice(length - 4, length)}`
}

/**
Expand Down
14 changes: 13 additions & 1 deletion packages/huma-shared/src/utils/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isSolanaTestnet, SolanaChainEnum } from '../solana/chain'
import { CHAINS } from './chain'
import { CHAINS, NETWORK_TYPE } from './chain'

const getDevPrefix = (isDev = false) => (isDev ? 'dev.' : '')

Expand Down Expand Up @@ -44,6 +44,11 @@ const getIdentityAPIUrl = (chainId: number, isDev = false) =>
isDev,
)}.identity-verification.huma.finance`

const getIdentityAPIUrlV2 = (networkType: NETWORK_TYPE, isDev = false) =>
`https://${getDevPrefix(
isDev,
)}${networkType}.identity-verification.huma.finance`

const getAuthServiceUrl = (chainId: number, isDev = false) =>
`https://${getNetworkAgnosticServiceUrlPrefix(
chainId,
Expand All @@ -67,6 +72,11 @@ const getCampaignAPIUrl = (isDev: boolean, pointsTestnetExperience: boolean) =>
pointsTestnetExperience ? 'testnet.' : 'mainnet.'
}campaign-points.huma.finance/graphql`

const getCampaignAPIUrlV2 = (networkType: NETWORK_TYPE, isDev: boolean) =>
`https://${getDevPrefix(
isDev,
)}${networkType}.campaign-points.huma.finance/graphql`

const getSolanaGraphAPIUrl = (
isDev: boolean,
pointsTestnetExperience: boolean,
Expand Down Expand Up @@ -108,9 +118,11 @@ export const configUtil = {
getEABaseUrlV1,
getRequestAPIUrl,
getIdentityAPIUrl,
getIdentityAPIUrlV2,
getAuthServiceUrl,
getKYCProviderBaseUrl,
getCampaignAPIUrl,
getCampaignAPIUrlV2,
getSolanaGraphAPIUrl,
DEFAULT_CHAIN_ID,
}
10 changes: 10 additions & 0 deletions packages/huma-shared/src/utils/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ export const EARejectReason = 'Your wallet does not meet qualifications'
export const EARejectMessage =
'Based on your wallet transaction history your application was not approved.'

export const COMMON_ERROR_MESSAGE =
'Sorry, there was an error. Please try again.'

export enum CURRENCY_CODE {
USD = 840,
}

export const CAMPAIGN_REFERENCE_CODE = 'CAMPAIGN_REFERENCE_CODE'

export const BP_FACTOR_NUMBER = 10000

export enum HUMA_ACCOUNT_EXCEPTION {
AccountTokenNotFoundException = 'AccountTokenNotFoundException',
InvalidAccountTokenException = 'InvalidAccountTokenException',
WalletNotSignedInException = 'WalletNotSignedInException',
WalletNotCreatedException = 'WalletNotCreatedException',
}
55 changes: 27 additions & 28 deletions packages/huma-shared/src/utils/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import axios, { AxiosRequestConfig } from 'axios'

axios.defaults.withCredentials = true

const getConfig = (customConfig: AxiosRequestConfig = {}) => ({
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
...customConfig,
})

export const requestGet = async <T>(
url: string,
customConfig: AxiosRequestConfig = {},
): Promise<T> => {
const config = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
...customConfig,
}

const config = getConfig(customConfig)
// @ts-ignore
return axios.get(url, {}, config).then((response) => response.data as T)
return axios.get(url, config).then((response) => response.data as T)
}

export const requestPost = async <T>(
Expand All @@ -25,15 +25,7 @@ export const requestPost = async <T>(
payload?: any,
customConfig: AxiosRequestConfig = {},
): Promise<T> => {
const config = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
...customConfig,
}

const config = getConfig(customConfig)
return (
axios
.post(url, payload, config)
Expand All @@ -48,19 +40,26 @@ export const requestPut = async <T>(
payload?: any,
customConfig: AxiosRequestConfig = {},
): Promise<T> => {
const config = {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
...customConfig,
}

const config = getConfig(customConfig)
return (
axios
.put(url, payload, config)
// @ts-ignore
.then((response) => response.data as T)
)
}

export const requestPatch = async <T>(
url: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
payload?: any,
customConfig: AxiosRequestConfig = {},
): Promise<T> => {
const config = getConfig(customConfig)
return (
axios
.patch(url, payload, config)
// @ts-ignore
.then((response) => response.data as T)
)
}
26 changes: 8 additions & 18 deletions packages/huma-shared/tests/utils/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,10 @@ describe('requestGet', () => {
const result = await requestGet(url)

expect(result).toEqual(responseData)
expect(axios.get).toHaveBeenCalledWith(
url,
{},
{
headers: { 'Content-Type': 'application/json' },
method: 'GET',
withCredentials: true,
},
)
expect(axios.get).toHaveBeenCalledWith(url, {
headers: { 'Content-Type': 'application/json' },
withCredentials: true,
})
})

it('throws an error if the GET request fails', async () => {
Expand All @@ -31,15 +26,10 @@ describe('requestGet', () => {

const url = 'https://example.com/api'
await expect(requestGet(url)).rejects.toThrow(errorMessage)
expect(axios.get).toHaveBeenCalledWith(
url,
{},
{
headers: { 'Content-Type': 'application/json' },
method: 'GET',
withCredentials: true,
},
)
expect(axios.get).toHaveBeenCalledWith(url, {
headers: { 'Content-Type': 'application/json' },
withCredentials: true,
})
})
})

Expand Down
13 changes: 7 additions & 6 deletions packages/huma-web-shared/src/hooks/useAuthErrorHandling/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { CHAIN_TYPE } from '@huma-finance/shared'
import { CHAIN_TYPE, HUMA_ACCOUNT_EXCEPTION } from '@huma-finance/shared'
import axios, { HttpStatusCode } from 'axios'
import { useCallback, useState } from 'react'
import { useAuthErrorHandlingEvm } from './useAuthErrorHandlingEvm'
Expand Down Expand Up @@ -35,13 +35,14 @@ export const useAuthErrorHandling = (
axios.isAxiosError(error) &&
error.response?.status === HttpStatusCode.Unauthorized &&
[
'IdTokenNotFoundException',
'InvalidIdTokenException',
'WalletMismatchException',
HUMA_ACCOUNT_EXCEPTION.AccountTokenNotFoundException,
HUMA_ACCOUNT_EXCEPTION.InvalidAccountTokenException,
].includes(error.response?.data?.detail?.type)

const isWalletNotCreatedError = error === 'WalletNotCreatedException'
const isWalletNotSignInError = error === 'WalletNotSignedInException'
const isWalletNotCreatedError =
error === HUMA_ACCOUNT_EXCEPTION.WalletNotCreatedException
const isWalletNotSignInError =
error === HUMA_ACCOUNT_EXCEPTION.WalletNotSignedInException

return {
isUnauthorizedError,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { JsonRpcProvider } from '@ethersproject/providers'
import { AuthService, CHAIN_TYPE } from '@huma-finance/shared'
import { AuthService, CHAIN_TYPE, CHAINS } from '@huma-finance/shared'
import { useWeb3React } from '@web3-react/core'
import { useEffect } from 'react'
import { SiweMessage } from 'siwe'
Expand Down Expand Up @@ -68,6 +68,14 @@ export const useAuthErrorHandlingEvm = (
return
}

const isChainSupported = Object.values(CHAINS).some(
(chain) => chain.id === chainId,
)

if (!isChainSupported) {
return
}

const {
isUnauthorizedError,
isWalletNotCreatedError,
Expand Down
35 changes: 35 additions & 0 deletions packages/huma-web-shared/src/hooks/useChainInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,38 @@ export const useChainInfo = (
provider,
}
}

export const useChainsInfo = (isDev: boolean) => {
const { account: evmAccount, chainId: evmChainId } = useChainInfo(
isDev,
CHAIN_TYPE.EVM,
)
const { account: solanaAccount, chainId: solanaChainId } = useChainInfo(
isDev,
CHAIN_TYPE.SOLANA,
)

return {
evmAccount,
evmChainId,
solanaAccount,
solanaChainId,
}
}

export const useActiveChainInfo = (
isDev: boolean,
activeNetwork: CHAIN_TYPE,
) => {
const evmChainInfo = useChainInfo(isDev, CHAIN_TYPE.EVM)
const solanaChainInfo = useChainInfo(isDev, CHAIN_TYPE.SOLANA)

switch (activeNetwork) {
case CHAIN_TYPE.EVM:
return evmChainInfo
case CHAIN_TYPE.SOLANA:
return solanaChainInfo
default:
return null
}
}
6 changes: 3 additions & 3 deletions packages/huma-web-shared/src/hooks/useDebouncedValue.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useEffect, useState } from 'react'

export const useDebouncedValue = (
value: number | string = '',
export const useDebouncedValue = <T extends number | string | undefined>(
value: T,
delay = 500,
): string | number => {
): T => {
const [debouncedValue, setDebouncedValue] = useState(value)

useEffect(() => {
Expand Down
2 changes: 0 additions & 2 deletions packages/huma-widget/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,6 @@ To be used when re-enabling autopay and other pool actions that require allowanc
| --- | --- | --- |
| poolInfo | <code>SolanaPoolInfo</code> | <p>The metadata of the pool.</p> |
| poolState | <code>SolanaPoolState</code> | <p>The current state config of the pool.</p> |
| pointsTestnetExperience | <code>boolean</code> | <p>If the user is in the testnet experience.</p> |
| handleClose | <code>function</code> | <p>Function to notify to close the widget modal when user clicks the 'x' close button.</p> |
| handleSuccess | <code>function</code> | <p>Optional function to notify that the lending pool supply action is successful.</p> |

Expand Down Expand Up @@ -747,7 +746,6 @@ To be used when re-enabling autopay and other pool actions that require allowanc
| Name | Type | Description |
| --- | --- | --- |
| poolName | <code>POOL\_NAME</code> | <p>The name of the pool.</p> |
| pointsTestnetExperience | <code>boolean</code> | <p>If the user is in the testnet experience.</p> |
| campaign | <code>Campaign</code> | <p>The campaign info.</p> |
| handleClose | <code>function</code> | <p>Function to notify to close the widget modal when user clicks the 'x' close button.</p> |
| handleSuccess | <code>function</code> | <p>Optional function to notify that the lending pool supply action is successful.</p> |
Expand Down
Loading

0 comments on commit dc79163

Please sign in to comment.