From 80af5dd1adbf5745758297eaae3c838ac2387c27 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Wed, 14 Jun 2023 14:49:04 -0400 Subject: [PATCH 01/19] Fix front-end TS issues --- apps/web/src/composables/ethers.ts | 7 +-- apps/web/src/composables/trezor.ts | 2 +- apps/web/src/composables/users.ts | 15 +---- apps/web/src/composables/wallet.ts | 27 +++++---- contracts/ethereum/docs/index.md | 88 +++++++++++++++--------------- 5 files changed, 66 insertions(+), 73 deletions(-) diff --git a/apps/web/src/composables/ethers.ts b/apps/web/src/composables/ethers.ts index 07a70f1aa..88c18e008 100644 --- a/apps/web/src/composables/ethers.ts +++ b/apps/web/src/composables/ethers.ts @@ -18,7 +18,7 @@ export default function useEthers() { method: 'wallet_addEthereumChain', params: [network] }) - } catch(error: any) { + } catch(error) { console.log(`Error occurred while adding network ${network.chainName}, Message: ${error.message} Code: ${error.code}`) } } @@ -205,8 +205,7 @@ export default function useEthers() { async function signEthersMessage(messageRequest: MessageRequest): Promise { const { providerString, message } = messageRequest const browserProvider = getBrowserProvider(providerString) - const web3Provider: ethers.providers.Web3Provider = - new ethers.providers.Web3Provider(browserProvider as EthersProvider) + const web3Provider: ethers.providers.Web3Provider = new ethers.providers.Web3Provider(browserProvider as EthersProvider) const signer = web3Provider.getSigner() const signature = await signer.signMessage(message) return signature @@ -226,7 +225,7 @@ export default function useEthers() { method:'wallet_switchEthereumChain', params: [{chainId: chainId}] }) - } catch(err: any){ + } catch (err) { console.log(`Error occurred while switching chain to chainId ${chainId}, err: ${err.message} code: ${err.code}`) if (err.code === 4902){ if (chainId === '5') { diff --git a/apps/web/src/composables/trezor.ts b/apps/web/src/composables/trezor.ts index 182bc0339..a0ec19553 100644 --- a/apps/web/src/composables/trezor.ts +++ b/apps/web/src/composables/trezor.ts @@ -83,7 +83,7 @@ export default function useTrezor() { signedMessage }) return await loginResponse.json() - } catch (error: any) { + } catch (error) { console.log(error) throw new Error(error) } diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index ccc7d4d90..374ab3fcf 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -1,12 +1,9 @@ -import { onMounted, ref } from 'vue' +import { ref } from 'vue' import { AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, Account, ExistingUserCheck } from '@casimir/types' -import { ethers } from 'ethers' import useEnvironment from '@/composables/environment' -import useContracts from '@/composables/contracts' -import useWallet from '@/composables/wallet' import * as Session from 'supertokens-web-js/recipe/session' -const { usersBaseURL, ethereumURL } = useEnvironment() +const { usersBaseURL } = useEnvironment() // 0xd557a5745d4560B24D36A68b52351ffF9c86A212 const session = ref(false) @@ -101,14 +98,6 @@ export default function useUsers () { return user } - // onMounted(async () => { - // const { getUserBalance } = useWallet() - // // Just get pools for primary account for demo - // user.value.balance = ethers.utils.formatEther(await getUserBalance(user.value.id)) - // user.value.pools = await getPools(user.value.id) - // subscribeToUserEvents() - // }) - async function removeAccount({ address, currency, ownerAddress, walletProvider }: RemoveAccountOptions) { address = address.toLowerCase() const requestOptions = { diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index 0dda0f296..b575c3fed 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -64,7 +64,7 @@ export default function useWallet() { * @param currency * @returns */ - async function connectWallet() { + async function connectWallet(): Promise { try { // Sign Up or Login if (!user?.value?.address) { await login() @@ -99,7 +99,7 @@ export default function useWallet() { } await setUserAccountBalances() console.log('user.value after connecting wallet :>> ', user.value) - return user.value + return } catch (error) { console.error('There was an error in connectWallet :>> ', error) } @@ -300,7 +300,7 @@ export default function useWallet() { } else { return await connectWallet() // sign up or add account } - } catch (error: any) { + } catch (error) { console.error('selectAddress error: ', error) throw new Error(error) } @@ -332,7 +332,7 @@ export default function useWallet() { const trezorAddresses = await getTrezorAddress[currency]() as CryptoAddress[] setUserAddresses(trezorAddresses) } - } catch (error: any) { + } catch (error) { console.error('There was an error in selectProvider :>> ', error) if (error.name === 'TransportStatusError') alert('Please enter your PIN and open the Ethereum application on your device.') } @@ -419,13 +419,18 @@ export default function useWallet() { } } - async function switchNetwork(chainId: string) { - if (selectedProvider.value === 'MetaMask') { - switchEthersNetwork('MetaMask', chainId) - } else if (selectedProvider.value === 'CoinbaseWallet') { - switchEthersNetwork('CoinbaseWallet', chainId) - } else { - alert('Switching networks is only supported for MetaMask and Coinbase Wallet') + async function switchNetwork(chainId: string): Promise { + try { + if (selectedProvider.value === 'MetaMask') { + switchEthersNetwork('MetaMask', chainId) + } else if (selectedProvider.value === 'CoinbaseWallet') { + switchEthersNetwork('CoinbaseWallet', chainId) + } else { + alert('Switching networks is only supported for MetaMask and Coinbase Wallet') + } + } catch (error) { + console.error(error) + return new Promise((resolve, reject) => reject(error)) } } diff --git a/contracts/ethereum/docs/index.md b/contracts/ethereum/docs/index.md index ffbadf017..c8c630cdc 100644 --- a/contracts/ethereum/docs/index.md +++ b/contracts/ethereum/docs/index.md @@ -2129,6 +2129,50 @@ _Send ETH to a user_ | user | address | The user address | | amount | uint256 | The amount of stake to send | +## MockFunctionsOracle + +### constructor + +```solidity +constructor() public +``` + +### getRegistry + +```solidity +function getRegistry() external view returns (address) +``` + +Returns the address of the registry contract + +#### Return Values + +| Name | Type | Description | +| ---- | ---- | ----------- | +| [0] | address | address The address of the registry contract | + +### sendRequest + +```solidity +function sendRequest(uint64 _subscriptionId, bytes _data, uint32 _gasLimit) external returns (bytes32 requestId) +``` + +Sends a request (encoded as data) using the provided subscriptionId + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| _subscriptionId | uint64 | A unique subscription ID allocated by billing system, a client can make requests from different contracts referencing the same subscription | +| _data | bytes | Encoded Chainlink Functions request data, use FunctionsClient API to encode a request | +| _gasLimit | uint32 | Gas limit for the fulfillment callback | + +#### Return Values + +| Name | Type | Description | +| ---- | ---- | ----------- | +| requestId | bytes32 | A unique request identifier (unique per DON) | + ## IDepositContract ### DepositEvent @@ -2225,47 +2269,3 @@ struct RegistrationParams { function registerUpkeep(struct KeeperRegistrarInterface.RegistrationParams requestParams) external returns (uint256) ``` -## MockFunctionsOracle - -### constructor - -```solidity -constructor() public -``` - -### getRegistry - -```solidity -function getRegistry() external view returns (address) -``` - -Returns the address of the registry contract - -#### Return Values - -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | address | address The address of the registry contract | - -### sendRequest - -```solidity -function sendRequest(uint64 _subscriptionId, bytes _data, uint32 _gasLimit) external returns (bytes32 requestId) -``` - -Sends a request (encoded as data) using the provided subscriptionId - -#### Parameters - -| Name | Type | Description | -| ---- | ---- | ----------- | -| _subscriptionId | uint64 | A unique subscription ID allocated by billing system, a client can make requests from different contracts referencing the same subscription | -| _data | bytes | Encoded Chainlink Functions request data, use FunctionsClient API to encode a request | -| _gasLimit | uint32 | Gas limit for the fulfillment callback | - -#### Return Values - -| Name | Type | Description | -| ---- | ---- | ----------- | -| requestId | bytes32 | A unique request identifier (unique per DON) | - From 42620e44c16796d1439bfcecd0fc5f3e32699e9f Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Thu, 15 Jun 2023 15:53:29 -0400 Subject: [PATCH 02/19] Add common error handling interface for login methods --- apps/web/src/composables/ethers.ts | 2 +- apps/web/src/composables/users.ts | 56 +++++--- apps/web/src/composables/wallet.ts | 128 +++++++++++------- common/types/src/index.ts | 2 + .../src/interfaces/ErrorSuccessInterface.ts | 5 + services/users/src/providers/db.ts | 2 +- services/users/src/routes/user.ts | 37 +++-- 7 files changed, 150 insertions(+), 82 deletions(-) create mode 100644 common/types/src/interfaces/ErrorSuccessInterface.ts diff --git a/apps/web/src/composables/ethers.ts b/apps/web/src/composables/ethers.ts index 88c18e008..6e2ac3cd8 100644 --- a/apps/web/src/composables/ethers.ts +++ b/apps/web/src/composables/ethers.ts @@ -151,7 +151,7 @@ export default function useEthers() { return maxAfterFees } - async function loginWithEthers(loginCredentials: LoginCredentials) { + async function loginWithEthers(loginCredentials: LoginCredentials){ const { provider, address, currency } = loginCredentials const browserProvider = getBrowserProvider(provider) const web3Provider: ethers.providers.Web3Provider = new ethers.providers.Web3Provider(browserProvider as EthersProvider) diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index 374ab3fcf..d542706e0 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -1,5 +1,5 @@ import { ref } from 'vue' -import { AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, Account, ExistingUserCheck } from '@casimir/types' +import { AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, Account, ExistingUserCheck, ErrorSuccessInterface } from '@casimir/types' import useEnvironment from '@/composables/environment' import * as Session from 'supertokens-web-js/recipe/session' @@ -11,18 +11,23 @@ const user = ref() export default function useUsers () { - async function addAccount(account: AddAccountOptions): Promise<{ error: boolean, message: string, data: UserWithAccounts | null }> { - const requestOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ account }) + async function addAccount(account: AddAccountOptions): Promise { + try { + const requestOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ account }) + } + const response = await fetch(`${usersBaseURL}/user/add-sub-account`, requestOptions) + const { error, message, data: userAccount } = await response.json() + user.value = userAccount + return { error, message, data: userAccount } + } catch (error) { + console.log('Error in addAccount in wallet.ts :>> ', error) + return { error: true, message: 'Error adding account', data: null } } - const response = await fetch(`${usersBaseURL}/user/add-sub-account`, requestOptions) - const { data: userAccount } = await response.json() - user.value = userAccount - return { error: false, message: `Account added to user: ${userAccount}`, data: userAccount } } async function checkIfPrimaryUserExists(provider: ProviderString, address: string): Promise { @@ -64,7 +69,7 @@ export default function useUsers () { try { session.value = await Session.doesSessionExist() if (session.value) { - const user = await getUser() + const { data: user } = await getUser() if (user) { setUser(user) return true @@ -86,16 +91,25 @@ export default function useUsers () { return message } - async function getUser() { - const requestOptions = { - method: 'GET', - headers: { - 'Content-Type': 'application/json' + async function getUser() : Promise { + try { + const requestOptions = { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } } + const response = await fetch(`${usersBaseURL}/user`, requestOptions) + const { user, error, message } = await response.json() + return { + error, + message, + data: user + } + } catch (error) { + console.log('Error in getUser in wallet.ts :>> ', error) + throw new Error('Error getting user from API') } - const response = await fetch(`${usersBaseURL}/user`, requestOptions) - const { user } = await response.json() - return user } async function removeAccount({ address, currency, ownerAddress, walletProvider }: RemoveAccountOptions) { diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index b575c3fed..133fb17e2 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -5,7 +5,7 @@ import useSolana from '@/composables/solana' import useTrezor from '@/composables/trezor' import useUsers from '@/composables/users' import useWalletConnect from '@/composables/walletConnect' -import { Account, CryptoAddress, Currency, ExistingUserCheck, LoginCredentials, MessageRequest, ProviderString, TransactionRequest } from '@casimir/types' +import { Account, CryptoAddress, Currency, ExistingUserCheck, LoginCredentials, MessageRequest, ProviderString, TransactionRequest, ErrorSuccessInterface } from '@casimir/types' import * as Session from 'supertokens-web-js/recipe/session' // Test ethereum send from address : 0xd557a5745d4560B24D36A68b52351ffF9c86A212 @@ -64,17 +64,16 @@ export default function useWallet() { * @param currency * @returns */ - async function connectWallet(): Promise { + async function connectWallet(): Promise { try { // Sign Up or Login if (!user?.value?.address) { await login() - const userResponse = await getUser() - if (!userResponse?.error) { - setUser(userResponse) + const getUserResponse = await getUser() + if (!getUserResponse?.error) { + setUser(getUserResponse.data) setPrimaryAddress(user?.value?.address as string) } loadingUserWallets.value = false - // router.push('/') } else { // Add account if it doesn't already exist const userAccountExists = user.value?.accounts?.some((account: Account | any) => account?.address === selectedAddress.value && account?.walletProvider === selectedProvider.value && account?.currency === selectedCurrency.value) if (userAccountExists) { @@ -90,18 +89,28 @@ export default function useWallet() { } const addAccountResponse = await addAccount(account) if (!addAccountResponse?.error) { - const userResponse = await getUser() - setUser(userResponse) + const getUserResponse = await getUser() + setUser(getUserResponse.data) setPrimaryAddress(user?.value?.address as string) - // router.push('/') + } else { + console.error('There was an error adding the account :>> ', addAccountResponse.message) + throw new Error(addAccountResponse.message) } } } await setUserAccountBalances() console.log('user.value after connecting wallet :>> ', user.value) - return + return { + error: false, + message: 'Successfully connected wallet', + data: user.value + } } catch (error) { console.error('There was an error in connectWallet :>> ', error) + return { + error: true, + message: `There was an error connecting your wallet: ${error}` + } } } @@ -186,22 +195,27 @@ export default function useWallet() { * @returns */ async function login() { - const loginCredentials = { - provider: selectedProvider.value, - address: selectedAddress.value, - currency: selectedCurrency.value || 'ETH' - } as LoginCredentials - if (ethersProviderList.includes(selectedProvider.value)) { - return await loginWithEthers(loginCredentials) - } else if (selectedProvider.value === 'Ledger') { - return await loginWithLedger(loginCredentials, selectedPathIndex.value) - } else if (selectedProvider.value === 'Trezor') { - return await loginWithTrezor(loginCredentials, selectedPathIndex.value) - } else if (selectedProvider.value === 'WalletConnect'){ - return await loginWithWalletConnect(loginCredentials) - } else { - // TODO: Implement this for other providers - console.log('Sign up not yet supported for this wallet provider') + try { + const loginCredentials = { + provider: selectedProvider.value, + address: selectedAddress.value, + currency: selectedCurrency.value || 'ETH' + } as LoginCredentials + if (ethersProviderList.includes(selectedProvider.value)) { + return await loginWithEthers(loginCredentials) + } else if (selectedProvider.value === 'Ledger') { + return await loginWithLedger(loginCredentials, selectedPathIndex.value) + } else if (selectedProvider.value === 'Trezor') { + return await loginWithTrezor(loginCredentials, selectedPathIndex.value) + } else if (selectedProvider.value === 'WalletConnect'){ + return await loginWithWalletConnect(loginCredentials) + } else { + // TODO: Implement this for other providers + console.log('Sign up not yet supported for this wallet provider') + } + } catch (error) { + console.error('There was an error in login :>> ', error) + throw new Error('There was an error logging in: ' + error) } } @@ -278,7 +292,7 @@ export default function useWallet() { * @param provider * @param currency */ - async function selectAddress(address: any, pathIndex?: string) : Promise { + async function selectAddress(address: any, pathIndex?: string) : Promise { try { address = trimAndLowercaseAddress(address) setSelectedAddress(address) @@ -287,7 +301,11 @@ export default function useWallet() { const { sameAddress, sameProvider } : ExistingUserCheck = await checkIfPrimaryUserExists(selectedProvider.value, selectedAddress.value) if (sameAddress && sameProvider ) { - return await connectWallet() // login + await connectWallet() // login + return { + error: false, + message: 'Address already exists as a primary address using this provider', + } } else if (sameAddress && !sameProvider) { // TODO: Handle this on front-end: do you want to change your primary provider? throw new Error('Address already exists as a primary address using another provider') @@ -298,21 +316,27 @@ export default function useWallet() { if (accountsIfSecondaryAddress.length) { throw new Error(`${selectedAddress.value} already exists as a secondary address on this/these account(s): ${JSON.stringify(accountsIfSecondaryAddress)}`) } else { - return await connectWallet() // sign up or add account + await connectWallet() // sign up or add account + return { + error: false, + message: 'Address does not exist as a primary address using this provider', + } } } catch (error) { console.error('selectAddress error: ', error) - throw new Error(error) + return { + error: true, + message: error.message + } } } - // TODO: Check if we can find a way to scroll through addresses on MetaMask and CoinbaseWallet /** * Sets the selected provider and returns the set of addresses available for the selected provider * @param provider * @param currency */ - async function selectProvider(provider: ProviderString, currency: Currency = 'ETH') { + async function selectProvider(provider: ProviderString, currency: Currency = 'ETH'): Promise { console.clear() try { if (provider === 'WalletConnect') { @@ -332,9 +356,17 @@ export default function useWallet() { const trezorAddresses = await getTrezorAddress[currency]() as CryptoAddress[] setUserAddresses(trezorAddresses) } + return { + error: false, + message: 'Successfully selected provider' + } } catch (error) { - console.error('There was an error in selectProvider :>> ', error) - if (error.name === 'TransportStatusError') alert('Please enter your PIN and open the Ethereum application on your device.') + console.error('selectProvider error: ', error) + return { + error: true, + message: error.message as string || 'Error selecting provider', + data: error.name as string || null + } } } @@ -374,17 +406,22 @@ export default function useWallet() { } async function setUserAccountBalances() { - if (user?.value?.accounts) { - const accounts = user.value.accounts - const accountsWithBalances = await Promise.all(accounts.map(async (account: Account) => { - const balance = await getAccountBalance(account) - return { - ...account, - balance - } - })) - user.value.accounts = accountsWithBalances - setUser(user.value) + try { + if (user?.value?.accounts) { + const accounts = user.value.accounts + const accountsWithBalances = await Promise.all(accounts.map(async (account: Account) => { + const balance = await getAccountBalance(account) + return { + ...account, + balance + } + })) + user.value.accounts = accountsWithBalances + setUser(user.value) + } + } catch (error) { + console.error('setUserAccountBalances error: ', error) + throw new Error('Error setting user account balances') } } @@ -456,7 +493,6 @@ export default function useWallet() { selectedProvider, sendTransaction, setPrimaryWalletAccount, - setUserAccountBalances, signMessage, switchNetwork, toAddress, diff --git a/common/types/src/index.ts b/common/types/src/index.ts index f708a56ed..1ed29d8c3 100644 --- a/common/types/src/index.ts +++ b/common/types/src/index.ts @@ -10,6 +10,7 @@ import { CryptoAddress } from './interfaces/CryptoAddress' import { Currency } from './interfaces/Currency' import { DeploymentConfig } from './interfaces/DeploymentConfig' import { EthersProvider } from './interfaces/EthersProvider' +import { ErrorSuccessInterface } from './interfaces/ErrorSuccessInterface' import { Event } from './interfaces/Event' import { ExistingUserCheck } from './interfaces/ExistingUserCheck' import { GasEstimate } from './interfaces/GasEstimate' @@ -38,6 +39,7 @@ export type { Currency, DeploymentConfig, EthersProvider, + ErrorSuccessInterface, Event, ExistingUserCheck, GasEstimate, diff --git a/common/types/src/interfaces/ErrorSuccessInterface.ts b/common/types/src/interfaces/ErrorSuccessInterface.ts new file mode 100644 index 000000000..7c7758b0a --- /dev/null +++ b/common/types/src/interfaces/ErrorSuccessInterface.ts @@ -0,0 +1,5 @@ +export interface ErrorSuccessInterface { + error: boolean; + message: string; + data?: any; +} \ No newline at end of file diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts index 971077fce..d886d0257 100644 --- a/services/users/src/providers/db.ts +++ b/services/users/src/providers/db.ts @@ -1,6 +1,6 @@ import { Postgres } from '@casimir/data' import { camelCase } from '@casimir/helpers' -import { Account, ProviderString, RemoveAccountOptions, User, UserAddedSuccess } from '@casimir/types' +import { Account, RemoveAccountOptions, User, UserAddedSuccess } from '@casimir/types' import useEthers from './ethers' const { generateNonce } = useEthers() diff --git a/services/users/src/routes/user.ts b/services/users/src/routes/user.ts index 70c33f0ad..6eabceeef 100644 --- a/services/users/src/routes/user.ts +++ b/services/users/src/routes/user.ts @@ -7,17 +7,27 @@ const router = express.Router() const { addAccount, getUser, updateUserAddress, removeAccount } = useDB() router.get('/', verifySession(), async (req: SessionRequest, res: express.Response) => { - const address = req.session?.getUserId().toLowerCase() as string - const user = await getUser(address) - const message = user ? 'User found' : 'User not found' - const error = user ? false : true - res.setHeader('Content-Type', 'application/json') - res.status(200) - res.json({ - message, - error, - user - }) + try { + const address = req.session?.getUserId().toLowerCase() as string + const user = await getUser(address) + const message = user ? 'User found' : 'User not found' + const error = user ? false : true + res.setHeader('Content-Type', 'application/json') + res.status(200) + res.json({ + message, + error, + user + }) + } catch (err) { + console.log('Error in / route of user.ts :>> ', err) + res.status(500) + res.json({ + message: 'Error getting user', + error: true, + user: null + }) + } }) router.post('/add-sub-account', verifySession(), async (req: SessionRequest, res: express.Response) => { @@ -47,11 +57,12 @@ router.post('/add-sub-account', verifySession(), async (req: SessionRequest, res data: user }) } catch (err) { - console.log('err :>> ', err) + console.log('Error in /add-sub-account route of user.ts :>> ', err) res.status(500) res.json({ message: 'Error adding account', - error: true + error: true, + data: null }) } }) From 86cf55b41b05f471802f122893cd35199e2f96e6 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 08:38:30 -0700 Subject: [PATCH 03/19] Remove unused method getEthersAddress --- apps/web/src/composables/ethers.ts | 8 ------- apps/web/src/composables/wallet.ts | 35 +----------------------------- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/apps/web/src/composables/ethers.ts b/apps/web/src/composables/ethers.ts index 6e2ac3cd8..be066616d 100644 --- a/apps/web/src/composables/ethers.ts +++ b/apps/web/src/composables/ethers.ts @@ -92,13 +92,6 @@ export default function useEthers() { } } - async function getEthersAddress (providerString: ProviderString) { - const provider = getBrowserProvider(providerString) - if (provider) { - return (await requestEthersAccount(provider as EthersProvider)) - } - } - async function getEthersAddressWithBalance (providerString: ProviderString) { const provider = getBrowserProvider(providerString) @@ -244,7 +237,6 @@ export default function useEthers() { estimateLegacyGasFee, ethersProviderList, getMaxETHAfterFees, - getEthersAddress, getEthersAddressWithBalance, getEthersBalance, getEthersBrowserSigner, diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index 133fb17e2..1a328a8e6 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -34,7 +34,7 @@ const selectedCurrency = ref('') const toAddress = ref('0x728474D29c2F81eb17a669a7582A2C17f1042b57') export default function useWallet() { - const { estimateEIP1559GasFee, ethersProviderList, getEthersAddress, getEthersAddressWithBalance, getEthersBalance, sendEthersTransaction, signEthersMessage, loginWithEthers, getEthersBrowserProviderSelectedCurrency, switchEthersNetwork } = useEthers() + const { estimateEIP1559GasFee, ethersProviderList, getEthersAddressWithBalance, getEthersBalance, sendEthersTransaction, signEthersMessage, loginWithEthers, getEthersBrowserProviderSelectedCurrency, switchEthersNetwork } = useEthers() const { getLedgerAddress, loginWithLedger, sendLedgerTransaction, signLedgerMessage } = useLedger() const { solanaProviderList, getSolanaAddress, sendSolanaTransaction, signSolanaMessage } = useSolana() const { getTrezorAddress, loginWithTrezor, sendTrezorTransaction, signTrezorMessage } = useTrezor() @@ -141,39 +141,6 @@ export default function useWallet() { } } - /** - * Retrieve the address from the selected provider - * @param provider - MetaMask, CoinbaseWallet, Ledger, Trezor, WalletConnect, etc. - * @param currency - ETH, BTC, IOTX, SOL, etc. - * @returns - */ - async function getConnectedAddressFromProvider(provider: ProviderString, currency?: Currency) { - try { - let address - setSelectedProvider(provider) - if (provider === 'WalletConnect') { - address = await getWalletConnectAddress() - } else if (ethersProviderList.includes(provider)) { - address = await getEthersAddress(provider) - } else if (solanaProviderList.includes(provider)) { - address = await getSolanaAddress(provider) - } else if (provider === 'IoPay') { - // address = await getIoPayAddress() - } else if (provider === 'Ledger') { - setSelectedCurrency(currency as Currency) - // Ask user to select an account - address = await getColdStorageAddress(provider, currency as Currency) - } else if (provider === 'Trezor') { - address = await getColdStorageAddress(provider, currency as Currency) - } else { - throw new Error('No provider selected') - } - return trimAndLowercaseAddress(address) as string - } catch (error) { - console.error(error) - } - } - // Do we need balance of active address only? // Or do we need balance of all addresses in accounts associated with user? // Is this calculated on front end or back end or both? From 8a5812ac4354798cf9d3d8ed669b77f851c68223 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 08:40:49 -0700 Subject: [PATCH 04/19] Remove unused method getSolanaAddress --- apps/web/src/composables/wallet.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index 1a328a8e6..88a1463d2 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -36,7 +36,7 @@ const toAddress = ref('0x728474D29c2F81eb17a669a7582A2C17f1042b57') export default function useWallet() { const { estimateEIP1559GasFee, ethersProviderList, getEthersAddressWithBalance, getEthersBalance, sendEthersTransaction, signEthersMessage, loginWithEthers, getEthersBrowserProviderSelectedCurrency, switchEthersNetwork } = useEthers() const { getLedgerAddress, loginWithLedger, sendLedgerTransaction, signLedgerMessage } = useLedger() - const { solanaProviderList, getSolanaAddress, sendSolanaTransaction, signSolanaMessage } = useSolana() + const { solanaProviderList, sendSolanaTransaction, signSolanaMessage } = useSolana() const { getTrezorAddress, loginWithTrezor, sendTrezorTransaction, signTrezorMessage } = useTrezor() const { user, getUser, setUser, addAccount, checkIfSecondaryAddress, checkIfPrimaryUserExists, removeAccount, updatePrimaryAddress } = useUsers() const { getWalletConnectAddress, loginWithWalletConnect, sendWalletConnectTransaction, signWalletConnectMessage } = useWalletConnect() From a68c91cf6609f5af7e346ee1a86bb11b83232c53 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 11:48:03 -0700 Subject: [PATCH 05/19] Handle errors from checkIfPrimaryUserExists in selectAddress --- apps/web/src/composables/auth.ts | 2 +- apps/web/src/composables/users.ts | 24 +++++++++++++++-------- apps/web/src/composables/wallet.ts | 4 ++-- services/users/src/providers/db.ts | 14 +++++++++----- services/users/src/routes/auth.ts | 31 +++++++++++++++++++++--------- services/users/src/routes/user.ts | 1 + 6 files changed, 51 insertions(+), 25 deletions(-) diff --git a/apps/web/src/composables/auth.ts b/apps/web/src/composables/auth.ts index f5d960e94..652a91e89 100644 --- a/apps/web/src/composables/auth.ts +++ b/apps/web/src/composables/auth.ts @@ -23,7 +23,7 @@ export default function useAuth() { }) } const res = await fetch(`${usersBaseURL}/auth/nonce`, requestOptions) - const { nonce } = (await res.json()) + const { data: nonce } = (await res.json()) const message = { domain, address, diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index d542706e0..c537b0afa 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -31,15 +31,23 @@ export default function useUsers () { } async function checkIfPrimaryUserExists(provider: ProviderString, address: string): Promise { - const requestOptions = { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - }, + try { + const requestOptions = { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + const response = await fetch(`${usersBaseURL}/auth/check-if-primary-address-exists/${provider}/${address}`, requestOptions) + const { error, message, data } = await response.json() + if (!error) { + return await data + } else { + throw new Error(message) + } + } catch (error) { + throw new Error(error.message) } - const response = await fetch(`${usersBaseURL}/auth/check-if-primary-address-exists/${provider}/${address}`, requestOptions) - const { sameAddress, sameProvider } = await response.json() - return { sameAddress, sameProvider } } async function checkIfSecondaryAddress(address: string) : Promise { diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index 88a1463d2..b76dc22ec 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -265,7 +265,6 @@ export default function useWallet() { setSelectedAddress(address) if (pathIndex) setSelectedPathIndex(pathIndex) - const { sameAddress, sameProvider } : ExistingUserCheck = await checkIfPrimaryUserExists(selectedProvider.value, selectedAddress.value) if (sameAddress && sameProvider ) { await connectWallet() // login @@ -290,7 +289,8 @@ export default function useWallet() { } } } catch (error) { - console.error('selectAddress error: ', error) + // TODO: @shanejearley - What do we want to do here? + console.error('selectAddress error: ', error.message) return { error: true, message: error.message diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts index d886d0257..42437576d 100644 --- a/services/users/src/providers/db.ts +++ b/services/users/src/providers/db.ts @@ -99,11 +99,15 @@ export default function useDB() { * @returns The user if found, otherwise undefined */ async function getUser(address: string) { - const text = 'SELECT u.*, json_agg(a.*) AS accounts FROM users u JOIN user_accounts ua ON u.id = ua.user_id JOIN accounts a ON ua.account_id = a.id WHERE u.address = $1 GROUP BY u.id' - const params = [address] - const rows = await postgres.query(text, params) - const user = rows[0] - return formatResult(user) as User + try { + const text = 'SELECT u.*, json_agg(a.*) AS accounts FROM users u JOIN user_accounts ua ON u.id = ua.user_id JOIN accounts a ON ua.account_id = a.id WHERE u.address = $1 GROUP BY u.id' + const params = [address] + const rows = await postgres.query(text, params) + const user = rows[0] + return formatResult(user) as User + } catch (error) { + throw new Error('There was an error getting user from the database') + } } /** diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index 0d34cc5e4..a128b8e71 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -17,16 +17,22 @@ router.post('/nonce', async (req: express.Request, res: express.Response) => { res.status(200) res.json({ error: false, - nonce + message: 'Nonce retrieved', + data: nonce }) } else { res.status(404) - res.send() + res.json({ + error: true, + message: 'Error getting nonce' + }) } } catch (error) { - console.log('error in /nonce :>> ', error) res.status(500) - res.send() + res.json({ + error: true, + message: 'Error getting nonce' + }) } }) @@ -143,13 +149,20 @@ router.get('/check-if-primary-address-exists/:provider/:address', async (req: ex res.status(200) res.json({ error: false, - sameAddress, - sameProvider + message: 'Successfully checked if primary address exists', + data: { + sameAddress, + sameProvider + } }) - } catch (error) { - console.log('error in /get-user-by-address :>> ', error) + } catch (error: any) { + const { message } = error + res.setHeader('Content-Type', 'application/json') res.status(500) - res.send() + res.json({ + error: true, + message: message || 'Problem checking if primary address exists' + }) } }) diff --git a/services/users/src/routes/user.ts b/services/users/src/routes/user.ts index 6eabceeef..289296d60 100644 --- a/services/users/src/routes/user.ts +++ b/services/users/src/routes/user.ts @@ -8,6 +8,7 @@ const { addAccount, getUser, updateUserAddress, removeAccount } = useDB() router.get('/', verifySession(), async (req: SessionRequest, res: express.Response) => { try { + console.log('go to / in user.ts') const address = req.session?.getUserId().toLowerCase() as string const user = await getUser(address) const message = user ? 'User found' : 'User not found' From 11ba3f5739b120f99025c984df75b68a42b5e512 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 12:08:06 -0700 Subject: [PATCH 06/19] Handle errors from checkIfSecondaryAddress in selectAddress --- apps/web/src/composables/users.ts | 16 ++++++---------- apps/web/src/composables/wallet.ts | 2 +- services/users/src/providers/db.ts | 27 +++++++++++++++++---------- services/users/src/routes/auth.ts | 7 ++++--- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index c537b0afa..1aab4bb70 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -40,13 +40,10 @@ export default function useUsers () { } const response = await fetch(`${usersBaseURL}/auth/check-if-primary-address-exists/${provider}/${address}`, requestOptions) const { error, message, data } = await response.json() - if (!error) { - return await data - } else { - throw new Error(message) - } + if (error) throw new Error(message) + return data } catch (error) { - throw new Error(error.message) + throw new Error(error.message || 'Error checking if primary user exists') } } @@ -59,12 +56,11 @@ export default function useUsers () { } } const response = await fetch(`${usersBaseURL}/auth/check-secondary-address/${address}`, requestOptions) - const json = await response.json() - const { users } = json + const { error, message, data: users } = await response.json() + if (error) throw new Error(message) return users } catch (error) { - console.log('Error in checkIfSecondaryAddress in wallet.ts :>> ', error) - return [] as Account[] + throw new Error(error.message || 'Error checking if secondary address') } } diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index b76dc22ec..d26529bd1 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -290,7 +290,7 @@ export default function useWallet() { } } catch (error) { // TODO: @shanejearley - What do we want to do here? - console.error('selectAddress error: ', error.message) + console.error('Error in selectAddress: ', error.message) return { error: true, message: error.message diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts index 42437576d..d12f63b82 100644 --- a/services/users/src/providers/db.ts +++ b/services/users/src/providers/db.ts @@ -74,10 +74,14 @@ export default function useDB() { * @returns The account if found, otherwise undefined */ async function getAccounts(address: string): Promise { - const text = 'SELECT * FROM accounts WHERE address = $1;' - const params = [address.toLowerCase()] - const rows = await postgres.query(text, params) - return formatResult(rows) as Account[] + try { + const text = 'SELECT * FROM accounts WHERE address = $1;' + const params = [address.toLowerCase()] + const rows = await postgres.query(text, params) + return formatResult(rows) as Account[] + } catch (error) { + throw new Error('There was an error getting accounts from the database') + } } /** @@ -117,12 +121,15 @@ export default function useDB() { * @throws Error if the user is not found */ async function getUserById(id: string) { - const text = 'SELECT u.*, json_agg(a.*) AS accounts FROM users u JOIN user_accounts ua ON u.id = ua.user_id JOIN accounts a ON ua.account_id = a.id WHERE u.id = $1 GROUP BY u.id' - const params = [id] - const rows = await postgres.query(text, params) - const user = rows[0] - if (!user) throw new Error('User not found') - return formatResult(user) as User + try { + const text = 'SELECT u.*, json_agg(a.*) AS accounts FROM users u JOIN user_accounts ua ON u.id = ua.user_id JOIN accounts a ON ua.account_id = a.id WHERE u.id = $1 GROUP BY u.id' + const params = [id] + const rows = await postgres.query(text, params) + const user = rows[0] + return formatResult(user) as User + } catch (err) { + throw new Error('There was an error getting user by id from the database') + } } /** diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index a128b8e71..f7a9dcb2c 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -124,14 +124,15 @@ router.get('/check-secondary-address/:address', async (req: express.Request, res res.status(200) res.json({ error: false, - users + message: 'Successfully checked secondary address', + data: users }) - } catch (error) { + } catch (error: any) { res.setHeader('Content-Type', 'application/json') res.status(500) res.json({ error: true, - message: 'Problem checking secondary address' + message: error.message || 'Problem checking secondary address' }) } }) From d666d76f2079bf2bb07c29b592a17cd46f676e4e Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 12:37:56 -0700 Subject: [PATCH 07/19] Handle errors from signInWithEthereum in selectAddress --- apps/web/src/composables/auth.ts | 45 +++++++++++++++++------------- apps/web/src/composables/ethers.ts | 3 +- apps/web/src/composables/wallet.ts | 9 ++---- services/users/src/providers/db.ts | 3 +- services/users/src/routes/auth.ts | 4 +-- 5 files changed, 31 insertions(+), 33 deletions(-) diff --git a/apps/web/src/composables/auth.ts b/apps/web/src/composables/auth.ts index 652a91e89..f14b8aabe 100644 --- a/apps/web/src/composables/auth.ts +++ b/apps/web/src/composables/auth.ts @@ -13,27 +13,32 @@ export default function useAuth() { * @returns {Promise} - The response from the message request */ async function createSiweMessage(address: string, statement: string) { - const requestOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - address - }) - } - const res = await fetch(`${usersBaseURL}/auth/nonce`, requestOptions) - const { data: nonce } = (await res.json()) - const message = { - domain, - address, - statement, - uri: origin, - version: '1', - chainId: 5, - nonce + try { + const requestOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + address + }) + } + const res = await fetch(`${usersBaseURL}/auth/nonce`, requestOptions) + const { error, message: resMessage, data: nonce } = (await res.json()) + if (error) throw new Error(resMessage) + const message = { + domain, + address, + statement, + uri: origin, + version: '1', + chainId: 5, + nonce + } + return prepareMessage(message) + } catch (error) { + throw new Error(error.message || 'Error creating SIWE message') } - return prepareMessage(message) } /** diff --git a/apps/web/src/composables/ethers.ts b/apps/web/src/composables/ethers.ts index be066616d..1bfa20d31 100644 --- a/apps/web/src/composables/ethers.ts +++ b/apps/web/src/composables/ethers.ts @@ -161,8 +161,7 @@ export default function useEthers() { }) return await ethersLoginResponse.json() } catch (err) { - console.log('Error logging in: ', err) - return err + throw new Error(err.message) } } diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index d26529bd1..ce9077af5 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -106,11 +106,7 @@ export default function useWallet() { data: user.value } } catch (error) { - console.error('There was an error in connectWallet :>> ', error) - return { - error: true, - message: `There was an error connecting your wallet: ${error}` - } + throw new Error(error.message || 'There was an error connecting the wallet') } } @@ -181,8 +177,7 @@ export default function useWallet() { console.log('Sign up not yet supported for this wallet provider') } } catch (error) { - console.error('There was an error in login :>> ', error) - throw new Error('There was an error logging in: ' + error) + throw new Error(error.message || 'There was an error logging in') } } diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts index d12f63b82..106074721 100644 --- a/services/users/src/providers/db.ts +++ b/services/users/src/providers/db.ts @@ -184,8 +184,7 @@ export default function useDB() { await postgres.query(text, params) return nonce } catch (error) { - console.error('There was an error adding or updating the nonce in upsertNonce.', error) - return error as Error + throw new Error('There was an error upserting nonce in the database') } } diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index f7a9dcb2c..d1a2375f7 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -27,11 +27,11 @@ router.post('/nonce', async (req: express.Request, res: express.Response) => { message: 'Error getting nonce' }) } - } catch (error) { + } catch (error: any) { res.status(500) res.json({ error: true, - message: 'Error getting nonce' + message: error.message || 'Error getting nonce' }) } }) From 981a78ec9858ebacc8527189b17ca2ddb4e2736f Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 13:47:05 -0700 Subject: [PATCH 08/19] Complete error handling for sign up flow --- apps/web/src/composables/auth.ts | 24 ++++++++++------- apps/web/src/composables/ethers.ts | 5 ++-- services/users/src/providers/db.ts | 42 ++++++++++++++++++------------ services/users/src/routes/auth.ts | 20 +++++++++----- 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/apps/web/src/composables/auth.ts b/apps/web/src/composables/auth.ts index f14b8aabe..a87698de2 100644 --- a/apps/web/src/composables/auth.ts +++ b/apps/web/src/composables/auth.ts @@ -1,5 +1,5 @@ import useEnvironment from '@/composables/environment' -import { LoginCredentials } from '@casimir/types' +import { LoginCredentials, ErrorSuccessInterface } from '@casimir/types' const { domain, origin, usersBaseURL } = useEnvironment() @@ -48,15 +48,21 @@ export default function useAuth() { * @param {LoginCredentials} loginCredentials - The user's address, provider, currency, message, and signed message * @returns {Promise} - The response from the login request */ - async function signInWithEthereum(loginCredentials: LoginCredentials) { - const requestOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(loginCredentials) + async function signInWithEthereum(loginCredentials: LoginCredentials): Promise { + try { + const requestOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(loginCredentials) + } + const response = await fetch(`${usersBaseURL}/auth/login`, requestOptions) + const { error, message } = await response.json() + if (error) throw new Error(message) + } catch (error) { + throw new Error(error.message || 'Error signing in with Ethereum') } - return await fetch(`${usersBaseURL}/auth/login`, requestOptions) } return { diff --git a/apps/web/src/composables/ethers.ts b/apps/web/src/composables/ethers.ts index 1bfa20d31..5b5e3c982 100644 --- a/apps/web/src/composables/ethers.ts +++ b/apps/web/src/composables/ethers.ts @@ -144,7 +144,7 @@ export default function useEthers() { return maxAfterFees } - async function loginWithEthers(loginCredentials: LoginCredentials){ + async function loginWithEthers(loginCredentials: LoginCredentials): Promise{ const { provider, address, currency } = loginCredentials const browserProvider = getBrowserProvider(provider) const web3Provider: ethers.providers.Web3Provider = new ethers.providers.Web3Provider(browserProvider as EthersProvider) @@ -152,14 +152,13 @@ export default function useEthers() { const message = await createSiweMessage(address, 'Sign in with Ethereum to the app.') const signer = web3Provider.getSigner() const signedMessage = await signer.signMessage(message) - const ethersLoginResponse = await signInWithEthereum({ + await signInWithEthereum({ address, currency, message, provider, signedMessage }) - return await ethersLoginResponse.json() } catch (err) { throw new Error(err.message) } diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts index 106074721..5efcd83da 100644 --- a/services/users/src/providers/db.ts +++ b/services/users/src/providers/db.ts @@ -50,7 +50,7 @@ export default function useDB() { const accountAdded = await addAccount(account, createdAt) addedUser.accounts = [accountAdded] - + return formatResult(addedUser) } @@ -90,11 +90,15 @@ export default function useDB() { * @returns - The nonce if address is a pk on the table or undefined */ async function getNonce(address:string) { - const text = 'SELECT nonce FROM nonces WHERE address = $1;' - const params = [address] - const rows = await postgres.query(text, params) - const { nonce } = rows[0] - return formatResult(nonce) + try { + const text = 'SELECT nonce FROM nonces WHERE address = $1;' + const params = [address] + const rows = await postgres.query(text, params) + const { nonce } = rows[0] + return formatResult(nonce) + } catch (error) { + throw new Error('There was an error getting nonce from the database') + } } /** @@ -194,18 +198,24 @@ export default function useDB() { * @returns The formatted data */ function formatResult(result: any) { - if (result) { - for (const key in result) { - result[camelCase(key)] = result[key] - delete result[key] - - if (result[camelCase(key)].isArray()) { - result[camelCase(key)] = result[camelCase(key)].map((result: any) => { - return formatResult(result) - }) + try { + if (typeof result === 'string') return result + if (result) { + for (const key in result) { + if (key === camelCase(key)) continue + result[camelCase(key)] = result[key] + delete result[key] + if (Array.isArray(result[camelCase(key)])) { + console.log('result[camelCase(key)] :>> ', result[camelCase(key)]) + result[camelCase(key)] = result[camelCase(key)].map((result: any) => { + return formatResult(result) + }) + } } + return result } - return result + } catch (error) { + throw new Error('There was an error formatting the result') } } diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index d1a2375f7..79ed85e6c 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -41,8 +41,8 @@ router.post('/login', async (req: express.Request, res: express.Response) => { const { body } = req const loginCredentials = body const { provider, address, currency, message, signedMessage } = loginCredentials - const { parsedDomain, parsedNonce } = parseMessage(message) + console.log('00---------------------------------------00') const verifyDomain = parsedDomain ? verifyMessageDomain(parsedDomain) : false const verifyNonce = parsedNonce ? await verifyMessageNonce(address, parsedNonce) : false const verifySignature = verifyMessageSignature(loginCredentials) @@ -101,8 +101,12 @@ router.post('/login', async (req: express.Request, res: express.Response) => { }) } } - } catch (e) { - console.log('CAUGHT ERROR IN /siwe: ', e) + } catch (error: any) { + res.status(500) + res.json({ + error: true, + message: error.message || 'Error logging in' + }) } }) @@ -191,15 +195,19 @@ function parseNonce(msg: string) { function verifyMessageDomain(domain: string): boolean { const stage = process.env.STAGE if (stage === 'dev') { - return domain === 'localhost:3000' + return domain === 'localhost:3001' } else { return false } } async function verifyMessageNonce(address: string, msgNonce: string) : Promise { - const dbNonce = await getNonce(address) - return msgNonce === dbNonce + try { + const dbNonce = await getNonce(address) + return msgNonce === dbNonce + } catch (error) { + throw new Error('Problem verifying message nonce') + } } export default router \ No newline at end of file From 2647163ce0c3a56517da55af89cde45c70c1d593 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 15:37:14 -0700 Subject: [PATCH 09/19] Handle errors for getUser within connectWallet method --- apps/web/src/composables/users.ts | 3 +-- apps/web/src/composables/wallet.ts | 9 ++++++--- services/users/src/providers/db.ts | 1 - services/users/src/routes/auth.ts | 1 - 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index 1aab4bb70..2527f1a82 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -111,8 +111,7 @@ export default function useUsers () { data: user } } catch (error) { - console.log('Error in getUser in wallet.ts :>> ', error) - throw new Error('Error getting user from API') + throw new Error('Error getting user from API route') } } diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index ce9077af5..a7d2cafe8 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -68,10 +68,12 @@ export default function useWallet() { try { // Sign Up or Login if (!user?.value?.address) { await login() - const getUserResponse = await getUser() - if (!getUserResponse?.error) { - setUser(getUserResponse.data) + const { error, message, data: retrievedUser} = await getUser() + if (!error) { + setUser(retrievedUser) setPrimaryAddress(user?.value?.address as string) + } else { + throw new Error(message || 'There was an error getting the user') } loadingUserWallets.value = false } else { // Add account if it doesn't already exist @@ -106,6 +108,7 @@ export default function useWallet() { data: user.value } } catch (error) { + loadingUserWallets.value = false throw new Error(error.message || 'There was an error connecting the wallet') } } diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts index 5efcd83da..3a75b20a5 100644 --- a/services/users/src/providers/db.ts +++ b/services/users/src/providers/db.ts @@ -206,7 +206,6 @@ export default function useDB() { result[camelCase(key)] = result[key] delete result[key] if (Array.isArray(result[camelCase(key)])) { - console.log('result[camelCase(key)] :>> ', result[camelCase(key)]) result[camelCase(key)] = result[camelCase(key)].map((result: any) => { return formatResult(result) }) diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index 79ed85e6c..f06b5fd30 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -42,7 +42,6 @@ router.post('/login', async (req: express.Request, res: express.Response) => { const loginCredentials = body const { provider, address, currency, message, signedMessage } = loginCredentials const { parsedDomain, parsedNonce } = parseMessage(message) - console.log('00---------------------------------------00') const verifyDomain = parsedDomain ? verifyMessageDomain(parsedDomain) : false const verifyNonce = parsedNonce ? await verifyMessageNonce(address, parsedNonce) : false const verifySignature = verifyMessageSignature(loginCredentials) From 9bba7399328b42682c4cb281d198b3f1b59da011 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 15:49:08 -0700 Subject: [PATCH 10/19] More error handling cleanup within connectWallet --- apps/web/src/composables/users.ts | 3 +-- apps/web/src/composables/wallet.ts | 17 ++++++++--------- services/users/src/routes/user.ts | 2 -- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index 2527f1a82..0a93cad25 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -25,8 +25,7 @@ export default function useUsers () { user.value = userAccount return { error, message, data: userAccount } } catch (error) { - console.log('Error in addAccount in wallet.ts :>> ', error) - return { error: true, message: 'Error adding account', data: null } + throw new Error(error.message || 'Error adding account') } } diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index a7d2cafe8..5b385c505 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -89,15 +89,14 @@ export default function useWallet() { ownerAddress: user?.value?.address.toLowerCase() as string, walletProvider: selectedProvider.value } - const addAccountResponse = await addAccount(account) - if (!addAccountResponse?.error) { - const getUserResponse = await getUser() - setUser(getUserResponse.data) - setPrimaryAddress(user?.value?.address as string) - } else { - console.error('There was an error adding the account :>> ', addAccountResponse.message) - throw new Error(addAccountResponse.message) - } + const { error: addAccountError, message: addAccountMessage } = await addAccount(account) + if (addAccountError) throw new Error(addAccountMessage || 'There was an error adding the account') + + const { error: getUserError, message: getUserMessage, data: getUserData } = await getUser() + if (getUserError) throw new Error(getUserMessage || 'There was an error getting the user') + + setUser(getUserData) + setPrimaryAddress(user?.value?.address as string) } } await setUserAccountBalances() diff --git a/services/users/src/routes/user.ts b/services/users/src/routes/user.ts index 289296d60..679f279a1 100644 --- a/services/users/src/routes/user.ts +++ b/services/users/src/routes/user.ts @@ -8,7 +8,6 @@ const { addAccount, getUser, updateUserAddress, removeAccount } = useDB() router.get('/', verifySession(), async (req: SessionRequest, res: express.Response) => { try { - console.log('go to / in user.ts') const address = req.session?.getUserId().toLowerCase() as string const user = await getUser(address) const message = user ? 'User found' : 'User not found' @@ -21,7 +20,6 @@ router.get('/', verifySession(), async (req: SessionRequest, res: express.Respon user }) } catch (err) { - console.log('Error in / route of user.ts :>> ', err) res.status(500) res.json({ message: 'Error getting user', From 232d6e08c6d0d55c6b36661dde917b4378020632 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 20 Jun 2023 15:52:10 -0700 Subject: [PATCH 11/19] Add throw in setUserAccountBalances --- apps/web/src/composables/wallet.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index 5b385c505..b1bdbcace 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -135,7 +135,7 @@ export default function useWallet() { const balance = await getEthersBalance(account.address) return balance } catch (err) { - console.error('There was an error in getAccountBalance :>> ', err) + throw new Error(err.message || 'There was an error getting the account balance') } } @@ -384,7 +384,6 @@ export default function useWallet() { setUser(user.value) } } catch (error) { - console.error('setUserAccountBalances error: ', error) throw new Error('Error setting user account balances') } } From f11227e9785f2d3f8c08f0ebaf9b380da3d7fc30 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Wed, 21 Jun 2023 08:02:42 -0700 Subject: [PATCH 12/19] Finish up error handling within connectWallet --- apps/web/src/composables/auth.ts | 2 +- apps/web/src/composables/wallet.ts | 5 +- apps/web/src/layouts/default-layout.vue | 3 ++ services/users/src/providers/db.ts | 71 +++++++++++++++---------- services/users/src/routes/user.ts | 4 +- 5 files changed, 53 insertions(+), 32 deletions(-) diff --git a/apps/web/src/composables/auth.ts b/apps/web/src/composables/auth.ts index a87698de2..a9fe4672e 100644 --- a/apps/web/src/composables/auth.ts +++ b/apps/web/src/composables/auth.ts @@ -1,5 +1,5 @@ import useEnvironment from '@/composables/environment' -import { LoginCredentials, ErrorSuccessInterface } from '@casimir/types' +import { LoginCredentials } from '@casimir/types' const { domain, origin, usersBaseURL } = useEnvironment() diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index b1bdbcace..d67660e0e 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -69,6 +69,7 @@ export default function useWallet() { if (!user?.value?.address) { await login() const { error, message, data: retrievedUser} = await getUser() + console.log('retrievedUser :>> ', retrievedUser) if (!error) { setUser(retrievedUser) setPrimaryAddress(user?.value?.address as string) @@ -79,7 +80,7 @@ export default function useWallet() { } else { // Add account if it doesn't already exist const userAccountExists = user.value?.accounts?.some((account: Account | any) => account?.address === selectedAddress.value && account?.walletProvider === selectedProvider.value && account?.currency === selectedCurrency.value) if (userAccountExists) { - alert('A user account already exists; setting provider, address, and currency') + throw new Error('Account already exists on user.') } else { console.log('adding sub account') const account = { @@ -89,6 +90,7 @@ export default function useWallet() { ownerAddress: user?.value?.address.toLowerCase() as string, walletProvider: selectedProvider.value } + const { error: addAccountError, message: addAccountMessage } = await addAccount(account) if (addAccountError) throw new Error(addAccountMessage || 'There was an error adding the account') @@ -260,6 +262,7 @@ export default function useWallet() { try { address = trimAndLowercaseAddress(address) setSelectedAddress(address) + setSelectedCurrency('ETH') // TODO: Implement this for other currencies when supported. if (pathIndex) setSelectedPathIndex(pathIndex) const { sameAddress, sameProvider } : ExistingUserCheck = await checkIfPrimaryUserExists(selectedProvider.value, selectedAddress.value) diff --git a/apps/web/src/layouts/default-layout.vue b/apps/web/src/layouts/default-layout.vue index c59a2153b..64b04d02a 100644 --- a/apps/web/src/layouts/default-layout.vue +++ b/apps/web/src/layouts/default-layout.vue @@ -2,6 +2,7 @@ import { ref, onMounted, onUnmounted } from 'vue' import useWallet from '@/composables/wallet' +import useUser from '@/composables/users' const selectedAddress = ref(null as string | null) @@ -12,6 +13,8 @@ const { selectProvider, } = useWallet() +const { user } = useUser() + const show_setting_modal = ref(false) const openWalletConnect = ref(false) const openSelectAddressInput = ref(false) diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts index 3a75b20a5..8cd914e60 100644 --- a/services/users/src/providers/db.ts +++ b/services/users/src/providers/db.ts @@ -23,15 +23,19 @@ export default function useDB() { * @returns The new account */ async function addAccount(account: Account, createdAt?: string) : Promise { - if (!createdAt) createdAt = new Date().toISOString() - const { address, currency, userId, walletProvider } = account - const text = 'INSERT INTO accounts (address, currency, user_id, wallet_provider, created_at) VALUES ($1, $2, $3, $4, $5) RETURNING *;' - const params = [address, currency, userId, walletProvider, createdAt] - const rows = await postgres.query(text, params) - const accountAdded = rows[0] - const accountId = accountAdded.id - await addUserAccount(parseInt(userId), accountId) - return accountAdded as Account + try { + if (!createdAt) createdAt = new Date().toISOString() + const { address, currency, userId, walletProvider } = account + const text = 'INSERT INTO accounts (address, currency, user_id, wallet_provider, created_at) VALUES ($1, $2, $3, $4, $5) RETURNING *;' + const params = [address, currency, userId, walletProvider, createdAt] + const rows = await postgres.query(text, params) + const accountAdded = rows[0] + const accountId = accountAdded.id + await addUserAccount(parseInt(userId), accountId) + return accountAdded as Account + } catch (error) { + throw new Error('There was an error adding the account to the database') + } } /** @@ -197,26 +201,39 @@ export default function useDB() { * @param rows - The result date * @returns The formatted data */ - function formatResult(result: any) { - try { - if (typeof result === 'string') return result - if (result) { - for (const key in result) { - if (key === camelCase(key)) continue - result[camelCase(key)] = result[key] - delete result[key] - if (Array.isArray(result[camelCase(key)])) { - result[camelCase(key)] = result[camelCase(key)].map((result: any) => { - return formatResult(result) - }) - } - } - return result + function formatResult(obj: any) : any { + if (typeof obj !== 'object' || obj === null) { + // Return non-object values as is + return obj + } + + if (Array.isArray(obj)) { + // If obj is an array, map over each item and recursively call the function + return obj.map(item => formatResult(item)) + } + + const convertedObj: any = {} + + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + const camelCaseKey = camelCase(key) + const value = obj[key] + + if (typeof value === 'object' && value !== null) { + // Recursively convert nested objects + convertedObj[camelCaseKey] = formatResult(value) + } else { + // Convert key to camel case and assign the value + convertedObj[camelCaseKey] = value } - } catch (error) { - throw new Error('There was an error formatting the result') + } } - } + + return convertedObj + } + + + return { addAccount, diff --git a/services/users/src/routes/user.ts b/services/users/src/routes/user.ts index 679f279a1..f478f5a49 100644 --- a/services/users/src/routes/user.ts +++ b/services/users/src/routes/user.ts @@ -36,7 +36,7 @@ router.post('/add-sub-account', verifySession(), async (req: SessionRequest, res const { ownerAddress } = account const userSessionsAddress = req.session?.getUserId().toLowerCase() const validatedAddress = validateAddress(userSessionsAddress, ownerAddress) - if (!validatedAddress) { + if (!validatedAddress) { res.setHeader('Content-Type', 'application/json') res.status(200) res.json({ @@ -44,7 +44,6 @@ router.post('/add-sub-account', verifySession(), async (req: SessionRequest, res error: true, data: null }) - return } await addAccount(account) const user = await getUser(ownerAddress) @@ -56,7 +55,6 @@ router.post('/add-sub-account', verifySession(), async (req: SessionRequest, res data: user }) } catch (err) { - console.log('Error in /add-sub-account route of user.ts :>> ', err) res.status(500) res.json({ message: 'Error adding account', From 01570a61d0726af8672d0e7a6375b2bdd677c05d Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Wed, 21 Jun 2023 08:27:36 -0700 Subject: [PATCH 13/19] Rename ErrorSuccessInterface to ApiResponse and contain it to api composables --- apps/web/src/composables/users.ts | 16 +++---- apps/web/src/composables/wallet.ts | 46 ++++--------------- common/types/src/index.ts | 4 +- common/types/src/interfaces/ApiResponse.ts | 7 +++ .../src/interfaces/ErrorSuccessInterface.ts | 5 -- 5 files changed, 27 insertions(+), 51 deletions(-) create mode 100644 common/types/src/interfaces/ApiResponse.ts delete mode 100644 common/types/src/interfaces/ErrorSuccessInterface.ts diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index 0a93cad25..92748df45 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -1,5 +1,5 @@ import { ref } from 'vue' -import { AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, Account, ExistingUserCheck, ErrorSuccessInterface } from '@casimir/types' +import { AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, ExistingUserCheck, ApiResponse } from '@casimir/types' import useEnvironment from '@/composables/environment' import * as Session from 'supertokens-web-js/recipe/session' @@ -11,7 +11,7 @@ const user = ref() export default function useUsers () { - async function addAccount(account: AddAccountOptions): Promise { + async function addAccount(account: AddAccountOptions): Promise { try { const requestOptions = { method: 'POST', @@ -29,7 +29,7 @@ export default function useUsers () { } } - async function checkIfPrimaryUserExists(provider: ProviderString, address: string): Promise { + async function checkIfPrimaryUserExists(provider: ProviderString, address: string): Promise { try { const requestOptions = { method: 'GET', @@ -40,13 +40,13 @@ export default function useUsers () { const response = await fetch(`${usersBaseURL}/auth/check-if-primary-address-exists/${provider}/${address}`, requestOptions) const { error, message, data } = await response.json() if (error) throw new Error(message) - return data + return { error, message, data } } catch (error) { throw new Error(error.message || 'Error checking if primary user exists') } } - async function checkIfSecondaryAddress(address: string) : Promise { + async function checkIfSecondaryAddress(address: string) : Promise { try { const requestOptions = { method: 'GET', @@ -55,9 +55,9 @@ export default function useUsers () { } } const response = await fetch(`${usersBaseURL}/auth/check-secondary-address/${address}`, requestOptions) - const { error, message, data: users } = await response.json() + const { error, message, data } = await response.json() if (error) throw new Error(message) - return users + return { error, message, data } } catch (error) { throw new Error(error.message || 'Error checking if secondary address') } @@ -94,7 +94,7 @@ export default function useUsers () { return message } - async function getUser() : Promise { + async function getUser() : Promise { try { const requestOptions = { method: 'GET', diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index d67660e0e..f5c5fc2a4 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -5,7 +5,7 @@ import useSolana from '@/composables/solana' import useTrezor from '@/composables/trezor' import useUsers from '@/composables/users' import useWalletConnect from '@/composables/walletConnect' -import { Account, CryptoAddress, Currency, ExistingUserCheck, LoginCredentials, MessageRequest, ProviderString, TransactionRequest, ErrorSuccessInterface } from '@casimir/types' +import { Account, CryptoAddress, Currency, LoginCredentials, MessageRequest, ProviderString, TransactionRequest } from '@casimir/types' import * as Session from 'supertokens-web-js/recipe/session' // Test ethereum send from address : 0xd557a5745d4560B24D36A68b52351ffF9c86A212 @@ -64,7 +64,7 @@ export default function useWallet() { * @param currency * @returns */ - async function connectWallet(): Promise { + async function connectWallet(): Promise { try { // Sign Up or Login if (!user?.value?.address) { await login() @@ -103,11 +103,6 @@ export default function useWallet() { } await setUserAccountBalances() console.log('user.value after connecting wallet :>> ', user.value) - return { - error: false, - message: 'Successfully connected wallet', - data: user.value - } } catch (error) { loadingUserWallets.value = false throw new Error(error.message || 'There was an error connecting the wallet') @@ -258,14 +253,14 @@ export default function useWallet() { * @param provider * @param currency */ - async function selectAddress(address: any, pathIndex?: string) : Promise { + async function selectAddress(address: any, pathIndex?: string) : Promise { try { address = trimAndLowercaseAddress(address) setSelectedAddress(address) setSelectedCurrency('ETH') // TODO: Implement this for other currencies when supported. if (pathIndex) setSelectedPathIndex(pathIndex) - const { sameAddress, sameProvider } : ExistingUserCheck = await checkIfPrimaryUserExists(selectedProvider.value, selectedAddress.value) + const { data: { sameAddress, sameProvider } } = await checkIfPrimaryUserExists(selectedProvider.value, selectedAddress.value) if (sameAddress && sameProvider ) { await connectWallet() // login return { @@ -277,24 +272,12 @@ export default function useWallet() { throw new Error('Address already exists as a primary address using another provider') } - const accountsIfSecondaryAddress : Account[] | void = await checkIfSecondaryAddress(selectedAddress.value) - console.log('accountsIfSecondaryAddress :>> ', accountsIfSecondaryAddress) - if (accountsIfSecondaryAddress.length) { - throw new Error(`${selectedAddress.value} already exists as a secondary address on this/these account(s): ${JSON.stringify(accountsIfSecondaryAddress)}`) - } else { - await connectWallet() // sign up or add account - return { - error: false, - message: 'Address does not exist as a primary address using this provider', - } - } + const { data: accountsIfSecondaryAddress } = await checkIfSecondaryAddress(selectedAddress.value) + if (accountsIfSecondaryAddress.length) throw new Error(`${selectedAddress.value} already exists as a secondary address on this/these account(s): ${JSON.stringify(accountsIfSecondaryAddress)}`) + await connectWallet() // sign up or add account } catch (error) { // TODO: @shanejearley - What do we want to do here? - console.error('Error in selectAddress: ', error.message) - return { - error: true, - message: error.message - } + throw new Error(error.message || 'There was an error selecting address') } } @@ -303,7 +286,7 @@ export default function useWallet() { * @param provider * @param currency */ - async function selectProvider(provider: ProviderString, currency: Currency = 'ETH'): Promise { + async function selectProvider(provider: ProviderString, currency: Currency = 'ETH'): Promise { console.clear() try { if (provider === 'WalletConnect') { @@ -323,17 +306,8 @@ export default function useWallet() { const trezorAddresses = await getTrezorAddress[currency]() as CryptoAddress[] setUserAddresses(trezorAddresses) } - return { - error: false, - message: 'Successfully selected provider' - } } catch (error) { - console.error('selectProvider error: ', error) - return { - error: true, - message: error.message as string || 'Error selecting provider', - data: error.name as string || null - } + throw new Error(`Error selecting provider: ${error.message}`) } } diff --git a/common/types/src/index.ts b/common/types/src/index.ts index 1ed29d8c3..49bde75c2 100644 --- a/common/types/src/index.ts +++ b/common/types/src/index.ts @@ -10,7 +10,7 @@ import { CryptoAddress } from './interfaces/CryptoAddress' import { Currency } from './interfaces/Currency' import { DeploymentConfig } from './interfaces/DeploymentConfig' import { EthersProvider } from './interfaces/EthersProvider' -import { ErrorSuccessInterface } from './interfaces/ErrorSuccessInterface' +import { ApiResponse } from './interfaces/ApiResponse' import { Event } from './interfaces/Event' import { ExistingUserCheck } from './interfaces/ExistingUserCheck' import { GasEstimate } from './interfaces/GasEstimate' @@ -39,7 +39,7 @@ export type { Currency, DeploymentConfig, EthersProvider, - ErrorSuccessInterface, + ApiResponse, Event, ExistingUserCheck, GasEstimate, diff --git a/common/types/src/interfaces/ApiResponse.ts b/common/types/src/interfaces/ApiResponse.ts new file mode 100644 index 000000000..ce907466e --- /dev/null +++ b/common/types/src/interfaces/ApiResponse.ts @@ -0,0 +1,7 @@ +import { ExistingUserCheck } from './ExistingUserCheck' + +export interface ApiResponse { + error: boolean; + message: string; + data?: any | ExistingUserCheck; // TODO: Can expand this to include more types +} \ No newline at end of file diff --git a/common/types/src/interfaces/ErrorSuccessInterface.ts b/common/types/src/interfaces/ErrorSuccessInterface.ts deleted file mode 100644 index 7c7758b0a..000000000 --- a/common/types/src/interfaces/ErrorSuccessInterface.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface ErrorSuccessInterface { - error: boolean; - message: string; - data?: any; -} \ No newline at end of file From 2ac5787231adde68988f68b82e65b68a3539b7fd Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Wed, 21 Jun 2023 08:28:57 -0700 Subject: [PATCH 14/19] Small refactor for readability --- apps/web/src/composables/wallet.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index f5c5fc2a4..d4c2b356b 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -69,13 +69,9 @@ export default function useWallet() { if (!user?.value?.address) { await login() const { error, message, data: retrievedUser} = await getUser() - console.log('retrievedUser :>> ', retrievedUser) - if (!error) { - setUser(retrievedUser) - setPrimaryAddress(user?.value?.address as string) - } else { - throw new Error(message || 'There was an error getting the user') - } + if (error) throw new Error(message || 'There was an error getting the user') + setUser(retrievedUser) + setPrimaryAddress(user?.value?.address as string) loadingUserWallets.value = false } else { // Add account if it doesn't already exist const userAccountExists = user.value?.accounts?.some((account: Account | any) => account?.address === selectedAddress.value && account?.walletProvider === selectedProvider.value && account?.currency === selectedCurrency.value) From 61a97c915dad3cc08e7d0a659dbd499b2525de02 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Wed, 21 Jun 2023 15:02:12 -0700 Subject: [PATCH 15/19] Move two endpoints from auth to user route --- apps/web/src/composables/users.ts | 4 +- services/users/src/routes/auth.ts | 67 +------------------------------ services/users/src/routes/user.ts | 67 ++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 69 deletions(-) diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index 92748df45..665b50af3 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -37,7 +37,7 @@ export default function useUsers () { 'Content-Type': 'application/json' } } - const response = await fetch(`${usersBaseURL}/auth/check-if-primary-address-exists/${provider}/${address}`, requestOptions) + const response = await fetch(`${usersBaseURL}/user/check-if-primary-address-exists/${provider}/${address}`, requestOptions) const { error, message, data } = await response.json() if (error) throw new Error(message) return { error, message, data } @@ -54,7 +54,7 @@ export default function useUsers () { 'Content-Type': 'application/json' } } - const response = await fetch(`${usersBaseURL}/auth/check-secondary-address/${address}`, requestOptions) + const response = await fetch(`${usersBaseURL}/user/check-secondary-address/${address}`, requestOptions) const { error, message, data } = await response.json() if (error) throw new Error(message) return { error, message, data } diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index f06b5fd30..1a170868b 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -5,7 +5,7 @@ import useEthers from '../providers/ethers' import { Account, User } from '@casimir/types' const { verifyMessageSignature } = useEthers() -const { addUser, getAccounts, getNonce, getUser, getUserById, upsertNonce } = useDB() +const { addUser, getNonce, getUser, upsertNonce } = useDB() const router = express.Router() router.post('/nonce', async (req: express.Request, res: express.Response) => { @@ -109,71 +109,6 @@ router.post('/login', async (req: express.Request, res: express.Response) => { } }) -router.get('/check-secondary-address/:address', async (req: express.Request, res: express.Response) => { - try { - const { params } = req - const { address } = params - const accounts = await getAccounts(address) - const users = await Promise.all(accounts.map(async account => { - const { userId } = account - const user = await getUserById(userId) - const { address, walletProvider } = user - return { - address: maskAddress(address), - walletProvider, - } - })) - res.setHeader('Content-Type', 'application/json') - res.status(200) - res.json({ - error: false, - message: 'Successfully checked secondary address', - data: users - }) - } catch (error: any) { - res.setHeader('Content-Type', 'application/json') - res.status(500) - res.json({ - error: true, - message: error.message || 'Problem checking secondary address' - }) - } -}) - -router.get('/check-if-primary-address-exists/:provider/:address', async (req: express.Request, res: express.Response) => { - try { - const { params } = req - const { address, provider } = params - const user = await getUser(address) - const userAddress = user?.address - const userProvider = user?.walletProvider - const sameAddress = userAddress === address - const sameProvider = userProvider === provider - res.setHeader('Content-Type', 'application/json') - res.status(200) - res.json({ - error: false, - message: 'Successfully checked if primary address exists', - data: { - sameAddress, - sameProvider - } - }) - } catch (error: any) { - const { message } = error - res.setHeader('Content-Type', 'application/json') - res.status(500) - res.json({ - error: true, - message: message || 'Problem checking if primary address exists' - }) - } -}) - -function maskAddress(address: string) { - return address.slice(0, 6) + '...' + address.slice(-4) -} - function parseDomain(msg: string) { const uri = msg.split('URI:')[1].split('Version:')[0].trim() const parsedUri = uri.split('://')[1].split('/')[0] diff --git a/services/users/src/routes/user.ts b/services/users/src/routes/user.ts index f478f5a49..5452f2d03 100644 --- a/services/users/src/routes/user.ts +++ b/services/users/src/routes/user.ts @@ -4,7 +4,7 @@ import { SessionRequest } from 'supertokens-node/framework/express' import useDB from '../providers/db' const router = express.Router() -const { addAccount, getUser, updateUserAddress, removeAccount } = useDB() +const { addAccount, getAccounts, getUser, getUserById, updateUserAddress, removeAccount } = useDB() router.get('/', verifySession(), async (req: SessionRequest, res: express.Response) => { try { @@ -29,6 +29,67 @@ router.get('/', verifySession(), async (req: SessionRequest, res: express.Respon } }) +router.get('/check-if-primary-address-exists/:provider/:address', async (req: express.Request, res: express.Response) => { + try { + const { params } = req + const { address, provider } = params + const user = await getUser(address) + const userAddress = user?.address + const userProvider = user?.walletProvider + const sameAddress = userAddress === address + const sameProvider = userProvider === provider + res.setHeader('Content-Type', 'application/json') + res.status(200) + res.json({ + error: false, + message: 'Successfully checked if primary address exists', + data: { + sameAddress, + sameProvider + } + }) + } catch (error: any) { + const { message } = error + res.setHeader('Content-Type', 'application/json') + res.status(500) + res.json({ + error: true, + message: message || 'Problem checking if primary address exists' + }) + } +}) + +router.get('/check-secondary-address/:address', async (req: express.Request, res: express.Response) => { + try { + const { params } = req + const { address } = params + const accounts = await getAccounts(address) + const users = await Promise.all(accounts.map(async account => { + const { userId } = account + const user = await getUserById(userId) + const { address, walletProvider } = user + return { + address: maskAddress(address), + walletProvider, + } + })) + res.setHeader('Content-Type', 'application/json') + res.status(200) + res.json({ + error: false, + message: 'Successfully checked secondary address', + data: users + }) + } catch (error: any) { + res.setHeader('Content-Type', 'application/json') + res.status(500) + res.json({ + error: true, + message: error.message || 'Problem checking secondary address' + }) + } +}) + router.post('/add-sub-account', verifySession(), async (req: SessionRequest, res: express.Response) => { try { console.log('ADDING ACCOUNT!') @@ -136,6 +197,10 @@ router.put('/update-primary-account', verifySession(), async (req: SessionReques } }) +function maskAddress(address: string) { + return address.slice(0, 6) + '...' + address.slice(-4) +} + function validateAddress(userSessionsAddress:string | undefined, address:string) { return userSessionsAddress === address } From fb80222c14f236c83050ad8f5f61288cc47cee38 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Wed, 21 Jun 2023 15:19:02 -0700 Subject: [PATCH 16/19] Implement error handling middleware --- services/users/src/index.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/users/src/index.ts b/services/users/src/index.ts index 242e94ecd..d1e355b02 100644 --- a/services/users/src/index.ts +++ b/services/users/src/index.ts @@ -36,5 +36,19 @@ app.use('/seed', seed) /** Returns 401 to the client in the case of session related errors */ app.use(errorHandler()) +/* Handle 500 errors */ +app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => { + // Log the error stack trace + console.error(`Error stack trace in middleware: ${err.stack}`) + console.error(`Error message in middleware: ${err.message}`) + + // Check if headers have already been sent to the client + if (res.headersSent) { + return next(err) + } + console.log('res.statusMessage :>> ', res.statusMessage) + res.status(500).send('Server error.') +}) + app.listen(port) console.log(`Users server listening on port ${port}`) \ No newline at end of file From d6eaed81e272b319aaae9759de2fa7b72fb08a57 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Wed, 21 Jun 2023 17:42:07 -0700 Subject: [PATCH 17/19] Introduce error handling middleware --- services/users/src/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/users/src/index.ts b/services/users/src/index.ts index d1e355b02..7695d66c4 100644 --- a/services/users/src/index.ts +++ b/services/users/src/index.ts @@ -46,8 +46,11 @@ app.use((err: any, req: express.Request, res: express.Response, next: express.Ne if (res.headersSent) { return next(err) } - console.log('res.statusMessage :>> ', res.statusMessage) - res.status(500).send('Server error.') + + res.status(500).json({ + error: true, + message: 'Server error.' + }) }) app.listen(port) From 0596d9b152c79b462900e406cc7e05f4bdefa42a Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Thu, 22 Jun 2023 08:04:18 -0700 Subject: [PATCH 18/19] Update handling in auth route --- services/users/src/routes/auth.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index 1a170868b..34521c8b7 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -20,12 +20,6 @@ router.post('/nonce', async (req: express.Request, res: express.Response) => { message: 'Nonce retrieved', data: nonce }) - } else { - res.status(404) - res.json({ - error: true, - message: 'Error getting nonce' - }) } } catch (error: any) { res.status(500) From cdeb37d707496eb55bbaef6bc1f8d607f91ecfb4 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Thu, 22 Jun 2023 08:15:03 -0700 Subject: [PATCH 19/19] Fix error type on front end api calls --- apps/web/src/composables/auth.ts | 4 ++-- apps/web/src/composables/users.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/web/src/composables/auth.ts b/apps/web/src/composables/auth.ts index a9fe4672e..20cda6a56 100644 --- a/apps/web/src/composables/auth.ts +++ b/apps/web/src/composables/auth.ts @@ -36,7 +36,7 @@ export default function useAuth() { nonce } return prepareMessage(message) - } catch (error) { + } catch (error: any) { throw new Error(error.message || 'Error creating SIWE message') } } @@ -60,7 +60,7 @@ export default function useAuth() { const response = await fetch(`${usersBaseURL}/auth/login`, requestOptions) const { error, message } = await response.json() if (error) throw new Error(message) - } catch (error) { + } catch (error: any) { throw new Error(error.message || 'Error signing in with Ethereum') } } diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index 665b50af3..34350fa25 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -24,7 +24,7 @@ export default function useUsers () { const { error, message, data: userAccount } = await response.json() user.value = userAccount return { error, message, data: userAccount } - } catch (error) { + } catch (error: any) { throw new Error(error.message || 'Error adding account') } } @@ -41,7 +41,7 @@ export default function useUsers () { const { error, message, data } = await response.json() if (error) throw new Error(message) return { error, message, data } - } catch (error) { + } catch (error: any) { throw new Error(error.message || 'Error checking if primary user exists') } } @@ -58,7 +58,7 @@ export default function useUsers () { const { error, message, data } = await response.json() if (error) throw new Error(message) return { error, message, data } - } catch (error) { + } catch (error: any) { throw new Error(error.message || 'Error checking if secondary address') } } @@ -81,7 +81,7 @@ export default function useUsers () { } } return false - } catch (error) { + } catch (error: any) { console.log('Error in checkUserSessionExists in wallet.ts :>> ', error) return false } @@ -109,7 +109,7 @@ export default function useUsers () { message, data: user } - } catch (error) { + } catch (error: any) { throw new Error('Error getting user from API route') } }