From be2e67267225fc71cbaea223703c2493ea77f35f Mon Sep 17 00:00:00 2001 From: sophian Date: Thu, 31 Aug 2023 13:14:27 -0400 Subject: [PATCH 1/7] Send proper chain id to api --- centrifuge-app/src/pages/Onboarding/queries/useSignRemark.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/centrifuge-app/src/pages/Onboarding/queries/useSignRemark.ts b/centrifuge-app/src/pages/Onboarding/queries/useSignRemark.ts index 092d143cd4..562b1e3115 100644 --- a/centrifuge-app/src/pages/Onboarding/queries/useSignRemark.ts +++ b/centrifuge-app/src/pages/Onboarding/queries/useSignRemark.ts @@ -65,11 +65,13 @@ export const useSignRemark = ( // @ts-expect-error blockNumber = result.blockNumber.toString() } + const chainId = connectedNetwork === 'centrifuge' ? await centrifuge.getChainId() : connectedNetwork + await sendDocumentsToIssuer({ txHash, blockNumber, isEvmOnSubstrate, - chainId: connectedNetwork || 'centrifuge', + chainId: chainId || 136, }) setIsSubstrateTxLoading(false) } catch (e) { From 5b81c2907e2a5a1338e513ab366d47e363d7bf0b Mon Sep 17 00:00:00 2001 From: sophian Date: Thu, 31 Aug 2023 13:15:12 -0400 Subject: [PATCH 2/7] Fix typescript errors --- .../Onboarding/queries/useGlobalOnboardingStatus.ts | 2 +- .../controllers/user/getGlobalOnboardingStatus.ts | 12 +++--------- onboarding-api/src/database/index.ts | 4 ++-- onboarding-api/src/utils/fetchUser.ts | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts b/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts index 570129cdbf..29cb95c848 100644 --- a/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts +++ b/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts @@ -14,7 +14,7 @@ export const useGlobalOnboardingStatus = () => { const response = await fetch( `${import.meta.env.REACT_APP_ONBOARDING_API_URL}/getGlobalOnboardingStatus?address=${ selectedWallet.address - }&network=${selectedWallet.network}`, + }&network=${selectedWallet.network}&chainId=${wallet.connectedNetwork}`, { method: 'GET', headers: { diff --git a/onboarding-api/src/controllers/user/getGlobalOnboardingStatus.ts b/onboarding-api/src/controllers/user/getGlobalOnboardingStatus.ts index 26d9c99314..9cc601ed86 100644 --- a/onboarding-api/src/controllers/user/getGlobalOnboardingStatus.ts +++ b/onboarding-api/src/controllers/user/getGlobalOnboardingStatus.ts @@ -1,21 +1,15 @@ import { Request, Response } from 'express' -import { InferType, mixed, object, string } from 'yup' -import { SupportedNetworks } from '../../database' +import { walletSchema } from '../../database' import { fetchUser } from '../../utils/fetchUser' import { reportHttpError } from '../../utils/httpError' import { validateInput } from '../../utils/validateInput' -const getGlobalOnboardingStatusInput = object({ - address: string().required(), - network: mixed().required().oneOf(['evm', 'substrate']), -}) - export const getGlobalOnboardingStatusController = async ( - req: Request<{}, {}, {}, InferType>, + req: Request<{}, {}, {}, Request['wallet']>, res: Response ) => { try { - await validateInput(req.query, getGlobalOnboardingStatusInput) + await validateInput(req.query, walletSchema) const user = await fetchUser(req.query, { suppressError: true }) diff --git a/onboarding-api/src/database/index.ts b/onboarding-api/src/database/index.ts index adb63287f1..fc7b26a829 100644 --- a/onboarding-api/src/database/index.ts +++ b/onboarding-api/src/database/index.ts @@ -22,7 +22,7 @@ const uboSchema = object({ countryOfCitizenship: string().required(), }) -const walletSchema = object({ +export const walletSchema = object({ evm: array().of(string()), substrate: array().of(string()), evmOnSubstrate: array().of(string()), @@ -115,7 +115,7 @@ export const individualUserSchema = object({ investorType: string().default('individual') as StringSchema, wallets: walletSchema, kycReference: string().optional(), - email: string().default(null).nullable(), // TODO: coming soon + email: string().default(null).nullable(), name: string().required(), dateOfBirth: string().required(), countryOfCitizenship: string().required(), // TODO: validate with list of countries diff --git a/onboarding-api/src/utils/fetchUser.ts b/onboarding-api/src/utils/fetchUser.ts index 0ca7cc18ca..91de34c831 100644 --- a/onboarding-api/src/utils/fetchUser.ts +++ b/onboarding-api/src/utils/fetchUser.ts @@ -25,7 +25,7 @@ export async function fetchUser(wallet: Request['wallet'], options?: OptionsO if (!userSnapshotOnOtherNetwork.empty) { const { user, id } = userSnapshotOnOtherNetwork.docs.map((doc) => ({ user: doc.data(), id: doc.id }))[0] await validateAndWriteToFirestore( - { address: id, network }, + { address: id, network, chainId: wallet.chainId }, { wallets: { ...user.wallets, From 19c6095ec373642d612999e3c4a769c095dd27bd Mon Sep 17 00:00:00 2001 From: sophian Date: Fri, 1 Sep 2023 13:15:55 -0400 Subject: [PATCH 3/7] Fix onboarding for algol/demo --- onboarding-api/.env.example | 16 +++++++++++++--- onboarding-api/src/utils/envCheck.ts | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/onboarding-api/.env.example b/onboarding-api/.env.example index 23f2d5e640..309a009571 100644 --- a/onboarding-api/.env.example +++ b/onboarding-api/.env.example @@ -1,6 +1,16 @@ +# VARIABLES +REDIRECT_URL=http://localhost:3000 +MEMBERLIST_ADMIN_PURE_PROXY=kAM1ELFDHdHeLDAkAdwEnfufoCL5hpUycGs4ZQkSQKVpHFoXm +COLLATOR_WSS_URL=wss://fullnode.algol.cntrfg.com/public-ws +RELAY_WSS_URL=wss://fullnode-relay.algol.cntrfg.com +INFURA_KEY=bf808e7d3d924fbeb74672d9341d0550 +EVM_NETWORK=goerli +ONBOARDING_STORAGE_BUCKET=centrifuge-onboarding-api-dev +# SECRETS SHUFTI_PRO_SECRET_KEY= SHUFTI_PRO_CLIENT_ID= -NODE_ENV=development JWT_SECRET= -REDIRECT_URL=http://localhost:3000 -SENDGRID_API_KEY= \ No newline at end of file +SENDGRID_API_KEY= +COOKIE_SECRET= +EVM_MEMBERLIST_ADMIN_PRIVATE_KEY= +PURE_PROXY_CONTROLLER_SEED= \ No newline at end of file diff --git a/onboarding-api/src/utils/envCheck.ts b/onboarding-api/src/utils/envCheck.ts index 2f3a112b8f..10c7d2e7d1 100644 --- a/onboarding-api/src/utils/envCheck.ts +++ b/onboarding-api/src/utils/envCheck.ts @@ -1,2 +1,2 @@ -const devEnvs = ['demo', 'development', 'catalyst'] +const devEnvs = ['algol', 'development', 'catalyst'] export const IS_DEV_ENV = devEnvs.some((env) => process.env.COLLATOR_WSS_URL.includes(env)) From 2fe0da7f00456384af44522e2631b7f38fe9d6fd Mon Sep 17 00:00:00 2001 From: sophian Date: Fri, 1 Sep 2023 13:35:33 -0400 Subject: [PATCH 4/7] Fix global onboarding status --- .../queries/useGlobalOnboardingStatus.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts b/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts index 29cb95c848..26a5df0774 100644 --- a/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts +++ b/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts @@ -1,20 +1,24 @@ -import { useWallet } from '@centrifuge/centrifuge-react' +import { useCentrifuge, useWallet } from '@centrifuge/centrifuge-react' +import { encodeAddress } from '@polkadot/util-crypto' import { useQuery } from 'react-query' import { getSelectedWallet } from '../../../utils/getSelectedWallet' export const useGlobalOnboardingStatus = () => { const wallet = useWallet() + const cent = useCentrifuge() const selectedWallet = getSelectedWallet(wallet) const query = useQuery( ['global-onboarding-status', selectedWallet?.address], async () => { - if (selectedWallet) { + if (selectedWallet && selectedWallet.address) { + const chainId = await cent.getChainId() + const address = encodeAddress(selectedWallet.address, chainId) const response = await fetch( - `${import.meta.env.REACT_APP_ONBOARDING_API_URL}/getGlobalOnboardingStatus?address=${ - selectedWallet.address - }&network=${selectedWallet.network}&chainId=${wallet.connectedNetwork}`, + `${import.meta.env.REACT_APP_ONBOARDING_API_URL}/getGlobalOnboardingStatus?address=${address}&network=${ + selectedWallet.network + }&chainId=${wallet.connectedNetwork}`, { method: 'GET', headers: { From af8541ad9163ac67b2b6f6c2bcd07ee809bd1880 Mon Sep 17 00:00:00 2001 From: sophian Date: Fri, 1 Sep 2023 13:46:52 -0400 Subject: [PATCH 5/7] Fix global status for evm --- .../pages/Onboarding/queries/useGlobalOnboardingStatus.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts b/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts index 26a5df0774..5cbd235278 100644 --- a/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts +++ b/centrifuge-app/src/pages/Onboarding/queries/useGlobalOnboardingStatus.ts @@ -14,7 +14,10 @@ export const useGlobalOnboardingStatus = () => { async () => { if (selectedWallet && selectedWallet.address) { const chainId = await cent.getChainId() - const address = encodeAddress(selectedWallet.address, chainId) + const address = + selectedWallet.network === 'substrate' + ? encodeAddress(selectedWallet.address, chainId) + : selectedWallet.address const response = await fetch( `${import.meta.env.REACT_APP_ONBOARDING_API_URL}/getGlobalOnboardingStatus?address=${address}&network=${ selectedWallet.network From a852c19690f5767ded1477768983d6b6ae4d2f4e Mon Sep 17 00:00:00 2001 From: sophian Date: Fri, 1 Sep 2023 17:50:23 -0400 Subject: [PATCH 6/7] Update email dynamic data to match new templates --- .../src/controllers/user/updateInvestorStatus.ts | 4 ++-- onboarding-api/src/emails/sendApproveIssuerMessage.ts | 11 ++++++++--- onboarding-api/src/emails/sendDocumentsMessage.ts | 7 +++++++ .../src/emails/sendRejectInvestorMessage.ts | 8 +++++++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/onboarding-api/src/controllers/user/updateInvestorStatus.ts b/onboarding-api/src/controllers/user/updateInvestorStatus.ts index 3046246619..888517ff63 100644 --- a/onboarding-api/src/controllers/user/updateInvestorStatus.ts +++ b/onboarding-api/src/controllers/user/updateInvestorStatus.ts @@ -106,13 +106,13 @@ export const updateInvestorStatusController = async ( metadata, countersignedAgreementPDF ), - sendApproveIssuerMessage(wallet.address, metadata, tranche as Pool['tranches'][0], countersignedAgreementPDF), + sendApproveIssuerMessage(wallet, metadata, tranche as Pool['tranches'][0], countersignedAgreementPDF), validateAndWriteToFirestore(wallet, updatedUser, user.investorType, ['poolSteps']), ]) return res.status(200).send({ status: 'approved', poolId, trancheId, txHash }) } else if (user?.email && status === 'rejected') { await Promise.all([ - sendRejectInvestorMessage(user.email, metadata), + sendRejectInvestorMessage(user.email, tranche as Pool['tranches'][0], metadata), validateAndWriteToFirestore(wallet, updatedUser, user.investorType, ['poolSteps']), ]) return res.status(200).send({ status: 'rejected', poolId, trancheId }) diff --git a/onboarding-api/src/emails/sendApproveIssuerMessage.ts b/onboarding-api/src/emails/sendApproveIssuerMessage.ts index 48bc1f8bca..4226f3d20a 100644 --- a/onboarding-api/src/emails/sendApproveIssuerMessage.ts +++ b/onboarding-api/src/emails/sendApproveIssuerMessage.ts @@ -1,12 +1,15 @@ import { Pool } from '@centrifuge/centrifuge-js' +import { Request } from 'express' import { sendEmail, templateIds } from '.' +import { fetchUser } from '../utils/fetchUser' export const sendApproveIssuerMessage = async ( - walletAddress: string, + wallet: Request['wallet'], metadata: Record, tranche: Pool['tranches'][0], countersignedAgreementPDF: Uint8Array ) => { + const user = await fetchUser(wallet) const message = { personalizations: [ { @@ -16,7 +19,9 @@ export const sendApproveIssuerMessage = async ( }, ], dynamic_template_data: { - tokenName: tranche.currency.name, + trancheName: tranche.currency.name, + poolName: metadata?.pool.name, + investorEmail: user.email, }, }, ], @@ -28,7 +33,7 @@ export const sendApproveIssuerMessage = async ( attachments: [ { content: Buffer.from(countersignedAgreementPDF).toString('base64'), - filename: `${walletAddress}-${tranche.currency.name?.replaceAll(' ', '-')}-subscription-agreement.pdf`, + filename: `${wallet.address}-${tranche.currency.name?.replaceAll(' ', '-')}-subscription-agreement.pdf`, type: 'application/pdf', disposition: 'attachment', }, diff --git a/onboarding-api/src/emails/sendDocumentsMessage.ts b/onboarding-api/src/emails/sendDocumentsMessage.ts index 0332857c56..e33de61118 100644 --- a/onboarding-api/src/emails/sendDocumentsMessage.ts +++ b/onboarding-api/src/emails/sendDocumentsMessage.ts @@ -2,6 +2,7 @@ import { Request } from 'express' import * as jwt from 'jsonwebtoken' import { sendEmail, templateIds } from '.' import { onboardingBucket } from '../database' +import { fetchUser } from '../utils/fetchUser' import { HttpError } from '../utils/httpError' import { NetworkSwitch } from '../utils/networks/networkSwitch' @@ -11,6 +12,7 @@ export type UpdateInvestorStatusPayload = { trancheId: string } +// send documents to issuer to approve or reject the prospective investor export const sendDocumentsMessage = async ( wallet: Request['wallet'], poolId: string, @@ -19,6 +21,8 @@ export const sendDocumentsMessage = async ( debugEmail?: string ) => { const { metadata, pool } = await new NetworkSwitch(wallet.network).getPoolById(poolId) + const tranche = pool?.tranches.find((t) => t.id === trancheId) + const investorEmail = (await fetchUser(wallet)).email const payload: UpdateInvestorStatusPayload = { wallet, poolId, trancheId } const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '14d', @@ -48,6 +52,9 @@ export const sendDocumentsMessage = async ( token )}&status=approved&metadata=${pool?.metadata}&network=${wallet.network}`, disclaimerLink: `${process.env.REDIRECT_URL}/disclaimer`, + poolName: metadata?.pool.name, + trancheName: tranche?.currency.name, + investorEmail, }, }, ], diff --git a/onboarding-api/src/emails/sendRejectInvestorMessage.ts b/onboarding-api/src/emails/sendRejectInvestorMessage.ts index dd512cc910..9dd4b4ac88 100644 --- a/onboarding-api/src/emails/sendRejectInvestorMessage.ts +++ b/onboarding-api/src/emails/sendRejectInvestorMessage.ts @@ -1,6 +1,11 @@ +import { Pool } from '@centrifuge/centrifuge-js' import { sendEmail, templateIds } from '.' -export const sendRejectInvestorMessage = async (to: string, metadata: Record) => { +export const sendRejectInvestorMessage = async ( + to: string, + tranche: Pool['tranches'][0], + metadata: Record +) => { const message = { personalizations: [ { @@ -12,6 +17,7 @@ export const sendRejectInvestorMessage = async (to: string, metadata: Record Date: Fri, 1 Sep 2023 18:09:35 -0400 Subject: [PATCH 7/7] Remove duplicate pool name --- onboarding-api/src/emails/sendApproveInvestorMessage.ts | 1 - onboarding-api/src/emails/sendApproveIssuerMessage.ts | 1 - onboarding-api/src/emails/sendDocumentsMessage.ts | 1 - onboarding-api/src/emails/sendRejectInvestorMessage.ts | 1 - 4 files changed, 4 deletions(-) diff --git a/onboarding-api/src/emails/sendApproveInvestorMessage.ts b/onboarding-api/src/emails/sendApproveInvestorMessage.ts index 7edea5a9a1..28f41948d9 100644 --- a/onboarding-api/src/emails/sendApproveInvestorMessage.ts +++ b/onboarding-api/src/emails/sendApproveInvestorMessage.ts @@ -17,7 +17,6 @@ export const sendApproveInvestorMessage = async ( }, ], dynamic_template_data: { - poolName: poolMetadata?.pool.name, trancheName: tranche?.currency.name, poolUrl: `${process.env.REDIRECT_URL}/pools/${poolId}`, }, diff --git a/onboarding-api/src/emails/sendApproveIssuerMessage.ts b/onboarding-api/src/emails/sendApproveIssuerMessage.ts index 4226f3d20a..382c5957e3 100644 --- a/onboarding-api/src/emails/sendApproveIssuerMessage.ts +++ b/onboarding-api/src/emails/sendApproveIssuerMessage.ts @@ -20,7 +20,6 @@ export const sendApproveIssuerMessage = async ( ], dynamic_template_data: { trancheName: tranche.currency.name, - poolName: metadata?.pool.name, investorEmail: user.email, }, }, diff --git a/onboarding-api/src/emails/sendDocumentsMessage.ts b/onboarding-api/src/emails/sendDocumentsMessage.ts index e33de61118..3034f58382 100644 --- a/onboarding-api/src/emails/sendDocumentsMessage.ts +++ b/onboarding-api/src/emails/sendDocumentsMessage.ts @@ -52,7 +52,6 @@ export const sendDocumentsMessage = async ( token )}&status=approved&metadata=${pool?.metadata}&network=${wallet.network}`, disclaimerLink: `${process.env.REDIRECT_URL}/disclaimer`, - poolName: metadata?.pool.name, trancheName: tranche?.currency.name, investorEmail, }, diff --git a/onboarding-api/src/emails/sendRejectInvestorMessage.ts b/onboarding-api/src/emails/sendRejectInvestorMessage.ts index 9dd4b4ac88..cacf7d04af 100644 --- a/onboarding-api/src/emails/sendRejectInvestorMessage.ts +++ b/onboarding-api/src/emails/sendRejectInvestorMessage.ts @@ -15,7 +15,6 @@ export const sendRejectInvestorMessage = async ( }, ], dynamic_template_data: { - poolName: metadata?.pool.name, issuerEmail: metadata.pool.issuer.email, trancheName: tranche?.currency.name, },