@huma-finance/widgets 0.0.59-beta.487 → 0.0.59-beta.488
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +1 -0
- package/dist/cjs/index.cjs +1093 -323
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1094 -325
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/src/components/Activity.tsx +1 -2
- package/src/components/ApproveAllowanceModal.tsx +1 -1
- package/src/components/ApproveAllowanceModalV2.tsx +1 -1
- package/src/components/ChooseAmountModal.tsx +10 -8
- package/src/components/ConfirmTransferModal.tsx +3 -3
- package/src/components/CreditLine/borrow/1-Evaluation.tsx +2 -2
- package/src/components/ErrorModal.tsx +3 -10
- package/src/components/InputAmountModal.tsx +7 -5
- package/src/components/Lend/supply/1-Evaluation/EvaluationEA.tsx +1 -1
- package/src/components/Lend/supply/1-Evaluation/EvaluationKYC.tsx +1 -1
- package/src/components/Lend/supplyV2/2-Evaluation.tsx +28 -329
- package/src/components/Lend/supplyV2/3-ChooseAmount.tsx +52 -9
- package/src/components/Lend/supplyV2/6-Success.tsx +49 -6
- package/src/components/Lend/supplyV2/7-Notifications.tsx +22 -3
- package/src/components/Lend/supplyV2/8-PointsEarned.tsx +219 -0
- package/src/components/Lend/supplyV2/components/PersonaEvaluation.tsx +427 -0
- package/src/components/Lend/supplyV2/components/SecuritizeEvaluation.tsx +345 -0
- package/src/components/Lend/supplyV2/index.tsx +61 -5
- package/src/components/Lend/withdrawV2/1-ConfirmTransfer.tsx +1 -1
- package/src/components/Notifi/NotifiSubscriptionModal.tsx +1 -1
- package/src/components/SignIn.tsx +8 -3
- package/src/components/TxDoneModal.tsx +22 -3
- package/src/components/WrapperModal.tsx +1 -1
- package/src/components/humaModal/HumaModal.tsx +4 -3
- package/src/components/humaModal/HumaModalHeader.tsx +1 -0
- package/src/components/icons/congratulations.svg +54 -0
- package/src/components/icons/huma-points.svg +15 -0
- package/src/components/icons/index.tsx +15 -0
- package/src/components/icons/ribbon.svg +9 -0
- package/src/store/widgets.reducers.ts +0 -1
- package/src/store/widgets.store.ts +1 -0
- package/src/theme/components.ts +2 -1
- package/src/theme/palette.ts +7 -7
- package/src/theme/typography.ts +0 -1
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CAMPAIGN_REFERENCE_CODE,
|
|
3
|
+
CampaignService,
|
|
4
|
+
checkIsDev,
|
|
5
|
+
formatNumber,
|
|
6
|
+
IdentityServiceV2,
|
|
7
|
+
IdentityVerificationStatusV2,
|
|
8
|
+
KYCCopy,
|
|
9
|
+
PoolInfoV2,
|
|
10
|
+
TrancheType,
|
|
11
|
+
useAuthErrorHandling,
|
|
12
|
+
VerificationStatusResultV2,
|
|
13
|
+
} from '@huma-finance/shared'
|
|
14
|
+
import { Box, css, useTheme } from '@mui/material'
|
|
15
|
+
import { useWeb3React } from '@web3-react/core'
|
|
16
|
+
import { BigNumber } from 'ethers'
|
|
17
|
+
import Persona, { Client } from 'persona'
|
|
18
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
19
|
+
|
|
20
|
+
import { Campaign } from '..'
|
|
21
|
+
import { useAppDispatch } from '../../../../hooks/useRedux'
|
|
22
|
+
import { setError, setStep } from '../../../../store/widgets.reducers'
|
|
23
|
+
import { WIDGET_STEP } from '../../../../store/widgets.store'
|
|
24
|
+
import { BottomButton } from '../../../BottomButton'
|
|
25
|
+
import { ApproveLenderImg } from '../../../images'
|
|
26
|
+
import { LoadingModal } from '../../../LoadingModal'
|
|
27
|
+
import { WrapperModal } from '../../../WrapperModal'
|
|
28
|
+
|
|
29
|
+
type LoadingType = 'verificationStatus' | 'startKYC' | 'approveLender'
|
|
30
|
+
|
|
31
|
+
const LoadingCopiesByType: {
|
|
32
|
+
[key: string]: {
|
|
33
|
+
description: string
|
|
34
|
+
}
|
|
35
|
+
} = {
|
|
36
|
+
verificationStatus: {
|
|
37
|
+
description: `Checking your verification status...`,
|
|
38
|
+
},
|
|
39
|
+
startKYC: {
|
|
40
|
+
description: `Starting KYC...`,
|
|
41
|
+
},
|
|
42
|
+
approveLender: {
|
|
43
|
+
description: `Approving as lender...`,
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type Props = {
|
|
48
|
+
poolInfo: PoolInfoV2
|
|
49
|
+
isUniTranche: boolean
|
|
50
|
+
minDepositAmount: BigNumber
|
|
51
|
+
campaign?: Campaign
|
|
52
|
+
changeTranche: (tranche: TrancheType) => void
|
|
53
|
+
handleClose: () => void
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function PersonaEvaluation({
|
|
57
|
+
poolInfo,
|
|
58
|
+
isUniTranche,
|
|
59
|
+
minDepositAmount: minDepositAmountBN,
|
|
60
|
+
campaign,
|
|
61
|
+
changeTranche,
|
|
62
|
+
handleClose,
|
|
63
|
+
}: Props): React.ReactElement | null {
|
|
64
|
+
const theme = useTheme()
|
|
65
|
+
const isDev = checkIsDev()
|
|
66
|
+
const dispatch = useAppDispatch()
|
|
67
|
+
const { account, chainId } = useWeb3React()
|
|
68
|
+
const {
|
|
69
|
+
errorType,
|
|
70
|
+
setError: setAuthError,
|
|
71
|
+
isWalletOwnershipVerified,
|
|
72
|
+
isWalletOwnershipVerificationRequired,
|
|
73
|
+
} = useAuthErrorHandling(isDev)
|
|
74
|
+
const KYCCopies = poolInfo.KYC!.Persona!
|
|
75
|
+
const [loadingType, setLoadingType] = useState<LoadingType>()
|
|
76
|
+
const [kycCopy, setKYCCopy] = useState<KYCCopy>(KYCCopies.verifyIdentity)
|
|
77
|
+
const [inquiryId, setInquiryId] = useState<string>()
|
|
78
|
+
const [sessionToken, setSessionToken] = useState<string>()
|
|
79
|
+
const [verificationStatus, setVerificationStatus] =
|
|
80
|
+
useState<VerificationStatusResultV2>()
|
|
81
|
+
const [showPersonaClient, setShowPersonaClient] = useState<boolean>(false)
|
|
82
|
+
const [campaignBasePoints, setCampaignBasePoints] = useState<number>(0)
|
|
83
|
+
const isKYCCompletedRef = useRef<boolean>(false)
|
|
84
|
+
const isActionOngoingRef = useRef<boolean>(false)
|
|
85
|
+
const isKYCResumedRef = useRef<boolean>(false)
|
|
86
|
+
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
const createNewWallet = async () => {
|
|
89
|
+
if (isWalletOwnershipVerified && campaign && account) {
|
|
90
|
+
await CampaignService.createNewWallet(
|
|
91
|
+
account,
|
|
92
|
+
localStorage.getItem(CAMPAIGN_REFERENCE_CODE) ?? undefined,
|
|
93
|
+
isDev,
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
createNewWallet()
|
|
98
|
+
}, [account, campaign, isDev, isWalletOwnershipVerified])
|
|
99
|
+
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
const getBasePoints = async () => {
|
|
102
|
+
if (campaign) {
|
|
103
|
+
const estimatedPoints = await CampaignService.getEstimatedPoints(
|
|
104
|
+
campaign.campaignGroupId,
|
|
105
|
+
minDepositAmountBN.toString(),
|
|
106
|
+
isDev,
|
|
107
|
+
)
|
|
108
|
+
const campaignPoints = estimatedPoints.find(
|
|
109
|
+
(item) => item.campaignId === campaign.id,
|
|
110
|
+
)
|
|
111
|
+
if (campaignPoints) {
|
|
112
|
+
const { juniorTranchePoints, seniorTranchePoints } = campaignPoints
|
|
113
|
+
if (isUniTranche) {
|
|
114
|
+
setCampaignBasePoints(juniorTranchePoints ?? 0)
|
|
115
|
+
} else {
|
|
116
|
+
setCampaignBasePoints(
|
|
117
|
+
juniorTranchePoints < seniorTranchePoints
|
|
118
|
+
? juniorTranchePoints
|
|
119
|
+
: seniorTranchePoints,
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
getBasePoints()
|
|
126
|
+
}, [campaign, isDev, isUniTranche, minDepositAmountBN])
|
|
127
|
+
|
|
128
|
+
const approveLender = useCallback(async () => {
|
|
129
|
+
try {
|
|
130
|
+
isActionOngoingRef.current = true
|
|
131
|
+
setLoadingType('approveLender')
|
|
132
|
+
await IdentityServiceV2.approveLender(
|
|
133
|
+
account!,
|
|
134
|
+
chainId!,
|
|
135
|
+
poolInfo.juniorTrancheVault,
|
|
136
|
+
isDev,
|
|
137
|
+
)
|
|
138
|
+
if (!isUniTranche) {
|
|
139
|
+
await IdentityServiceV2.approveLender(
|
|
140
|
+
account!,
|
|
141
|
+
chainId!,
|
|
142
|
+
poolInfo.seniorTrancheVault,
|
|
143
|
+
isDev,
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
if (isUniTranche) {
|
|
147
|
+
changeTranche('junior')
|
|
148
|
+
dispatch(setStep(WIDGET_STEP.ChooseAmount))
|
|
149
|
+
} else {
|
|
150
|
+
dispatch(setStep(WIDGET_STEP.ChooseTranche))
|
|
151
|
+
}
|
|
152
|
+
} finally {
|
|
153
|
+
isActionOngoingRef.current = false
|
|
154
|
+
setLoadingType(undefined)
|
|
155
|
+
}
|
|
156
|
+
}, [
|
|
157
|
+
account,
|
|
158
|
+
chainId,
|
|
159
|
+
changeTranche,
|
|
160
|
+
dispatch,
|
|
161
|
+
isDev,
|
|
162
|
+
isUniTranche,
|
|
163
|
+
poolInfo.juniorTrancheVault,
|
|
164
|
+
poolInfo.seniorTrancheVault,
|
|
165
|
+
])
|
|
166
|
+
|
|
167
|
+
const checkVerificationStatus = useCallback(async () => {
|
|
168
|
+
if (isActionOngoingRef.current || isKYCResumedRef.current) {
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
if (account && chainId) {
|
|
173
|
+
isActionOngoingRef.current = true
|
|
174
|
+
setLoadingType('verificationStatus')
|
|
175
|
+
const verificationStatus =
|
|
176
|
+
await IdentityServiceV2.getVerificationStatusV2(
|
|
177
|
+
account,
|
|
178
|
+
chainId,
|
|
179
|
+
isDev,
|
|
180
|
+
)
|
|
181
|
+
setVerificationStatus(verificationStatus)
|
|
182
|
+
setInquiryId(verificationStatus.personaInquiryId)
|
|
183
|
+
|
|
184
|
+
switch (verificationStatus.status) {
|
|
185
|
+
case IdentityVerificationStatusV2.NOT_STARTED: {
|
|
186
|
+
const startVerificationResult =
|
|
187
|
+
await IdentityServiceV2.startVerification(account, chainId, isDev)
|
|
188
|
+
setInquiryId(startVerificationResult.personaInquiryId)
|
|
189
|
+
setKYCCopy(KYCCopies.verifyIdentity)
|
|
190
|
+
setLoadingType(undefined)
|
|
191
|
+
break
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
case IdentityVerificationStatusV2.CREATED: {
|
|
195
|
+
setKYCCopy(KYCCopies.verifyIdentity)
|
|
196
|
+
setLoadingType(undefined)
|
|
197
|
+
break
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
case IdentityVerificationStatusV2.PENDING: {
|
|
201
|
+
if (!isKYCCompletedRef.current) {
|
|
202
|
+
const resumeVerificationResult =
|
|
203
|
+
await IdentityServiceV2.resumeVerification(
|
|
204
|
+
account,
|
|
205
|
+
chainId,
|
|
206
|
+
isDev,
|
|
207
|
+
)
|
|
208
|
+
verificationStatus.status = resumeVerificationResult.status
|
|
209
|
+
setVerificationStatus(verificationStatus)
|
|
210
|
+
setSessionToken(resumeVerificationResult.sessionToken)
|
|
211
|
+
setLoadingType(undefined)
|
|
212
|
+
isKYCResumedRef.current = true
|
|
213
|
+
} else {
|
|
214
|
+
setLoadingType('verificationStatus')
|
|
215
|
+
}
|
|
216
|
+
setKYCCopy(KYCCopies.verifyIdentity)
|
|
217
|
+
break
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
case IdentityVerificationStatusV2.EXPIRED: {
|
|
221
|
+
const resumeVerificationResult =
|
|
222
|
+
await IdentityServiceV2.resumeVerification(
|
|
223
|
+
account,
|
|
224
|
+
chainId,
|
|
225
|
+
isDev,
|
|
226
|
+
)
|
|
227
|
+
verificationStatus.status = resumeVerificationResult.status
|
|
228
|
+
setVerificationStatus(verificationStatus)
|
|
229
|
+
setSessionToken(resumeVerificationResult.sessionToken)
|
|
230
|
+
setKYCCopy(KYCCopies.verifyIdentity)
|
|
231
|
+
setLoadingType(undefined)
|
|
232
|
+
isKYCResumedRef.current = true
|
|
233
|
+
break
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
case IdentityVerificationStatusV2.APPROVED: {
|
|
237
|
+
await approveLender()
|
|
238
|
+
break
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
case IdentityVerificationStatusV2.DECLINED: {
|
|
242
|
+
setKYCCopy(KYCCopies.verificationDeclined)
|
|
243
|
+
setLoadingType(undefined)
|
|
244
|
+
break
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
case IdentityVerificationStatusV2.NEEDS_REVIEW: {
|
|
248
|
+
setKYCCopy(KYCCopies.verificationNeedsReview)
|
|
249
|
+
setLoadingType(undefined)
|
|
250
|
+
break
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
default:
|
|
254
|
+
break
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} catch (e: unknown) {
|
|
258
|
+
setAuthError(e)
|
|
259
|
+
} finally {
|
|
260
|
+
isActionOngoingRef.current = false
|
|
261
|
+
}
|
|
262
|
+
}, [KYCCopies, account, approveLender, chainId, isDev, setAuthError])
|
|
263
|
+
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
checkVerificationStatus()
|
|
266
|
+
}, [checkVerificationStatus])
|
|
267
|
+
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
if (isWalletOwnershipVerificationRequired && isWalletOwnershipVerified) {
|
|
270
|
+
checkVerificationStatus()
|
|
271
|
+
}
|
|
272
|
+
}, [
|
|
273
|
+
checkVerificationStatus,
|
|
274
|
+
isWalletOwnershipVerificationRequired,
|
|
275
|
+
isWalletOwnershipVerified,
|
|
276
|
+
])
|
|
277
|
+
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
const interval = setInterval(() => {
|
|
280
|
+
if (
|
|
281
|
+
verificationStatus?.status &&
|
|
282
|
+
[
|
|
283
|
+
IdentityVerificationStatusV2.CREATED,
|
|
284
|
+
IdentityVerificationStatusV2.PENDING,
|
|
285
|
+
].includes(verificationStatus.status)
|
|
286
|
+
) {
|
|
287
|
+
checkVerificationStatus()
|
|
288
|
+
}
|
|
289
|
+
}, 10 * 1000)
|
|
290
|
+
// eslint-disable-next-line consistent-return
|
|
291
|
+
return () => clearInterval(interval)
|
|
292
|
+
}, [checkVerificationStatus, verificationStatus?.status])
|
|
293
|
+
|
|
294
|
+
useEffect(() => {
|
|
295
|
+
if (errorType === 'NotSignedIn') {
|
|
296
|
+
setLoadingType(undefined)
|
|
297
|
+
setKYCCopy(KYCCopies.signInRequired)
|
|
298
|
+
} else if (errorType === 'UserRejected') {
|
|
299
|
+
dispatch(
|
|
300
|
+
setError({
|
|
301
|
+
errorMessage: 'User has rejected the transaction.',
|
|
302
|
+
}),
|
|
303
|
+
)
|
|
304
|
+
} else if (errorType === 'Other') {
|
|
305
|
+
dispatch(
|
|
306
|
+
setError({
|
|
307
|
+
errorMessage: 'Something went wrong. Please try again later.',
|
|
308
|
+
}),
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
}, [KYCCopies.signInRequired, dispatch, errorType])
|
|
312
|
+
|
|
313
|
+
useEffect(() => {
|
|
314
|
+
const modalElement = document.getElementById('huma-modal')
|
|
315
|
+
if (modalElement) {
|
|
316
|
+
modalElement.style.visibility = showPersonaClient ? 'hidden' : 'visible'
|
|
317
|
+
}
|
|
318
|
+
}, [showPersonaClient])
|
|
319
|
+
|
|
320
|
+
const startKYC = async () => {
|
|
321
|
+
isActionOngoingRef.current = true
|
|
322
|
+
isKYCResumedRef.current = false
|
|
323
|
+
setLoadingType('startKYC')
|
|
324
|
+
const client: Client = new Persona.Client({
|
|
325
|
+
inquiryId,
|
|
326
|
+
sessionToken,
|
|
327
|
+
onReady: () => {
|
|
328
|
+
client.open()
|
|
329
|
+
setShowPersonaClient(true)
|
|
330
|
+
},
|
|
331
|
+
onComplete: () => {
|
|
332
|
+
isKYCCompletedRef.current = true
|
|
333
|
+
isActionOngoingRef.current = false
|
|
334
|
+
setShowPersonaClient(false)
|
|
335
|
+
checkVerificationStatus()
|
|
336
|
+
},
|
|
337
|
+
onCancel: () => {
|
|
338
|
+
isActionOngoingRef.current = false
|
|
339
|
+
setShowPersonaClient(false)
|
|
340
|
+
setLoadingType(undefined)
|
|
341
|
+
},
|
|
342
|
+
onError: () => {
|
|
343
|
+
isActionOngoingRef.current = false
|
|
344
|
+
setShowPersonaClient(false)
|
|
345
|
+
setLoadingType(undefined)
|
|
346
|
+
},
|
|
347
|
+
})
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const handleAction = () => {
|
|
351
|
+
if (verificationStatus) {
|
|
352
|
+
switch (verificationStatus.status) {
|
|
353
|
+
case IdentityVerificationStatusV2.NOT_STARTED:
|
|
354
|
+
case IdentityVerificationStatusV2.CREATED:
|
|
355
|
+
case IdentityVerificationStatusV2.PENDING:
|
|
356
|
+
case IdentityVerificationStatusV2.EXPIRED:
|
|
357
|
+
startKYC()
|
|
358
|
+
break
|
|
359
|
+
|
|
360
|
+
case IdentityVerificationStatusV2.DECLINED:
|
|
361
|
+
case IdentityVerificationStatusV2.NEEDS_REVIEW:
|
|
362
|
+
handleClose()
|
|
363
|
+
break
|
|
364
|
+
|
|
365
|
+
default:
|
|
366
|
+
break
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const styles = {
|
|
372
|
+
iconWrapper: css`
|
|
373
|
+
${theme.cssMixins.rowCentered};
|
|
374
|
+
margin-top: ${theme.spacing(8)};
|
|
375
|
+
& > img {
|
|
376
|
+
width: 144px;
|
|
377
|
+
}
|
|
378
|
+
`,
|
|
379
|
+
description: css`
|
|
380
|
+
text-align: justify;
|
|
381
|
+
margin-top: ${theme.spacing(10)};
|
|
382
|
+
padding: ${theme.spacing(0, 2)};
|
|
383
|
+
font-weight: 400;
|
|
384
|
+
font-size: 16px;
|
|
385
|
+
color: ${theme.palette.text.primary};
|
|
386
|
+
`,
|
|
387
|
+
points: css`
|
|
388
|
+
color: ${theme.palette.primary.main};
|
|
389
|
+
font-weight: 700;
|
|
390
|
+
`,
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (!loadingType) {
|
|
394
|
+
return (
|
|
395
|
+
<WrapperModal title={kycCopy.title}>
|
|
396
|
+
<Box css={styles.iconWrapper}>
|
|
397
|
+
<img src={ApproveLenderImg} alt='approve-lender' />
|
|
398
|
+
</Box>
|
|
399
|
+
{campaign && kycCopy === KYCCopies.verifyIdentity ? (
|
|
400
|
+
<Box css={styles.description}>
|
|
401
|
+
<span>You’ll be rewarded with a minimum of</span>
|
|
402
|
+
<span css={styles.points}>
|
|
403
|
+
{' '}
|
|
404
|
+
{formatNumber(campaignBasePoints)} Huma points{' '}
|
|
405
|
+
</span>
|
|
406
|
+
<span>after completing KYC and your first investment.</span>
|
|
407
|
+
</Box>
|
|
408
|
+
) : (
|
|
409
|
+
<Box css={styles.description}>{kycCopy.description}</Box>
|
|
410
|
+
)}
|
|
411
|
+
|
|
412
|
+
{Boolean(kycCopy.buttonText) && (
|
|
413
|
+
<BottomButton variant='contained' onClick={handleAction}>
|
|
414
|
+
{kycCopy.buttonText}
|
|
415
|
+
</BottomButton>
|
|
416
|
+
)}
|
|
417
|
+
</WrapperModal>
|
|
418
|
+
)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return (
|
|
422
|
+
<LoadingModal
|
|
423
|
+
title='Lender Approval'
|
|
424
|
+
description={LoadingCopiesByType[loadingType].description}
|
|
425
|
+
/>
|
|
426
|
+
)
|
|
427
|
+
}
|