@huma-finance/widgets 0.0.73-beta.939 → 0.0.73-beta.950

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.
@@ -0,0 +1,3 @@
1
+ import { LoggingActions } from '../../../huma-web-shared/src';
2
+ declare const useLogOnFirstMount: (action: LoggingActions, data?: object) => void;
3
+ export default useLogOnFirstMount;
@@ -1,5 +1,6 @@
1
1
  import { Approval } from '../../../huma-shared/src';
2
2
  import { PayloadAction } from '@reduxjs/toolkit';
3
+ import { LoggingContext } from '../../../huma-web-shared/src';
3
4
  import { MultisendPayload, WIDGET_STEP, WidgetStream } from './widgets.store';
4
5
  export declare const widgetSlice: import('@reduxjs/toolkit').Slice<import('./widgets.store').WidgetState, {
5
6
  resetState: (state: import('immer/dist/internal').WritableDraft<import('./widgets.store').WidgetState>) => void;
@@ -29,6 +30,7 @@ export declare const widgetSlice: import('@reduxjs/toolkit').Slice<import('./wid
29
30
  setSolanaSignature: (state: import('immer/dist/internal').WritableDraft<import('./widgets.store').WidgetState>, { payload }: PayloadAction<string>) => void;
30
31
  setTxHash: (state: import('immer/dist/internal').WritableDraft<import('./widgets.store').WidgetState>, { payload }: PayloadAction<string>) => void;
31
32
  setPointsAccumulated: (state: import('immer/dist/internal').WritableDraft<import('./widgets.store').WidgetState>, { payload }: PayloadAction<number | undefined>) => void;
33
+ setLoggingContext: (state: import('immer/dist/internal').WritableDraft<import('./widgets.store').WidgetState>, { payload }: PayloadAction<LoggingContext>) => void;
32
34
  setError: (state: import('immer/dist/internal').WritableDraft<import('./widgets.store').WidgetState>, { payload, }: PayloadAction<{
33
35
  errorMessage: string;
34
36
  errorReason?: string;
@@ -51,6 +53,6 @@ export declare const resetState: import('@reduxjs/toolkit').ActionCreatorWithout
51
53
  }, "widget/setPaymentAmount">, setStream: import('@reduxjs/toolkit').ActionCreatorWithPayload<Partial<{
52
54
  borrowFlowrate: string;
53
55
  durationInSeconds: number;
54
- }>, "widget/setStream">, setMultisend: import('@reduxjs/toolkit').ActionCreatorWithPayload<MultisendPayload, "widget/setMultisend">, setSupplyAmount: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setSupplyAmount">, setWithdrawAmount: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setWithdrawAmount">, setWithdrawShares: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setWithdrawShares">, setRedeemAmount: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setRedeemAmount">, setRedeemShares: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setRedeemShares">, setSolanaSignature: import('@reduxjs/toolkit').ActionCreatorWithPayload<string, "widget/setSolanaSignature">, setTxHash: import('@reduxjs/toolkit').ActionCreatorWithPayload<string, "widget/setTxHash">, setPointsAccumulated: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<number | undefined, "widget/setPointsAccumulated">;
56
+ }>, "widget/setStream">, setMultisend: import('@reduxjs/toolkit').ActionCreatorWithPayload<MultisendPayload, "widget/setMultisend">, setSupplyAmount: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setSupplyAmount">, setWithdrawAmount: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setWithdrawAmount">, setWithdrawShares: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setWithdrawShares">, setRedeemAmount: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setRedeemAmount">, setRedeemShares: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, "widget/setRedeemShares">, setSolanaSignature: import('@reduxjs/toolkit').ActionCreatorWithPayload<string, "widget/setSolanaSignature">, setTxHash: import('@reduxjs/toolkit').ActionCreatorWithPayload<string, "widget/setTxHash">, setPointsAccumulated: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<number | undefined, "widget/setPointsAccumulated">, setLoggingContext: import('@reduxjs/toolkit').ActionCreatorWithPayload<LoggingContext, "widget/setLoggingContext">;
55
57
  declare const _default: import('redux').Reducer<import('./widgets.store').WidgetState>;
56
58
  export default _default;
@@ -1,2 +1,4 @@
1
+ import { LoggingContextHelper } from '../../../huma-web-shared/src';
1
2
  import { RootState } from '.';
2
3
  export declare const selectWidgetState: (state: RootState) => import('./widgets.store').WidgetState;
4
+ export declare const selectWidgetLoggingContext: (state: RootState) => LoggingContextHelper;
@@ -1,4 +1,5 @@
1
1
  import { Approval } from '../../../huma-shared/src';
2
+ import { LoggingContext } from '../../../huma-web-shared/src';
2
3
  export declare enum WIDGET_TYPE {
3
4
  BORROW = "BORROW",
4
5
  PAYMENT = "PAYMENT"
@@ -55,5 +56,6 @@ export type WidgetState = {
55
56
  solanaSignature?: string;
56
57
  pointsAccumulated?: number;
57
58
  txHash?: string;
59
+ loggingContext?: LoggingContext;
58
60
  };
59
61
  export declare const initialWidgetState: WidgetState;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huma-finance/widgets",
3
- "version": "0.0.73-beta.939+8b148f9",
3
+ "version": "0.0.73-beta.950+6da832c",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -22,9 +22,9 @@
22
22
  "@ethersproject/contracts": "^5.7.0",
23
23
  "@ethersproject/experimental": "^5.7.0",
24
24
  "@ethersproject/units": "^5.6.0",
25
- "@huma-finance/sdk": "^0.0.73-beta.939+8b148f9",
26
- "@huma-finance/shared": "^0.0.73-beta.939+8b148f9",
27
- "@huma-finance/web-shared": "^0.0.73-beta.939+8b148f9",
25
+ "@huma-finance/sdk": "^0.0.73-beta.950+6da832c",
26
+ "@huma-finance/shared": "^0.0.73-beta.950+6da832c",
27
+ "@huma-finance/web-shared": "^0.0.73-beta.950+6da832c",
28
28
  "@mui/x-date-pickers": "^5.0.7",
29
29
  "@notifi-network/notifi-frontend-client": "^1.1.2",
30
30
  "@notifi-network/notifi-react": "^1.1.2",
@@ -188,5 +188,5 @@
188
188
  "optionalDependencies": {
189
189
  "encoding": "^0.1.13"
190
190
  },
191
- "gitHead": "8b148f9340a401b544aa2739c82bcf839301a6d0"
191
+ "gitHead": "6da832ca26191b75c24a62dce5ae7e1b5929fbd0"
192
192
  }
@@ -3,6 +3,7 @@ import React from 'react'
3
3
 
4
4
  import { PersonaEvaluation } from '../components/PersonaEvaluation'
5
5
  import { Campaign } from '../supplyV2'
6
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
6
7
 
7
8
  type Props = {
8
9
  poolInfo: SolanaPoolInfo
@@ -19,6 +20,8 @@ export function Evaluation({
19
20
  documentHash,
20
21
  handleClose,
21
22
  }: Props): React.ReactElement | null {
23
+ useLogOnFirstMount('Evaluation')
24
+
22
25
  if (poolInfo.KYC?.Persona) {
23
26
  return (
24
27
  <PersonaEvaluation
@@ -8,6 +8,7 @@ import {
8
8
  import React from 'react'
9
9
 
10
10
  import { ApproveLenderBase } from '../components/ApproveLenderBase'
11
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
11
12
 
12
13
  type Props = {
13
14
  poolInfo: SolanaPoolInfo
@@ -22,6 +23,8 @@ export function ApproveLender({
22
23
  documentHash,
23
24
  changeTranche,
24
25
  }: Props): React.ReactElement | null {
26
+ useLogOnFirstMount('ApproveLender')
27
+
25
28
  const solanaChainInfo = SOLANA_CHAIN_INFO[poolInfo.chainId]
26
29
 
27
30
  return (
@@ -15,6 +15,7 @@ import { setStep } from '../../../store/widgets.reducers'
15
15
  import { WIDGET_STEP } from '../../../store/widgets.store'
16
16
  import { BottomButton } from '../../BottomButton'
17
17
  import { WrapperModal } from '../../WrapperModal'
18
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
18
19
 
19
20
  type Props = {
20
21
  poolUnderlyingToken: UnderlyingTokenInfo
@@ -27,6 +28,7 @@ export function ChooseTranche({
27
28
  selectedTranche,
28
29
  changeTranche,
29
30
  }: Props): React.ReactElement | null {
31
+ useLogOnFirstMount('ChooseTranche')
30
32
  const theme = useTheme()
31
33
  const dispatch = useAppDispatch()
32
34
 
@@ -12,6 +12,7 @@ import { useAppDispatch } from '../../../hooks/useRedux'
12
12
  import { setStep, setSupplyAmount } from '../../../store/widgets.reducers'
13
13
  import { WIDGET_STEP } from '../../../store/widgets.store'
14
14
  import { InputAmountModal } from '../../InputAmountModal'
15
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
15
16
 
16
17
  type Props = {
17
18
  poolInfo: SolanaPoolInfo
@@ -28,6 +29,7 @@ export function ChooseAmount({
28
29
  selectedTranche,
29
30
  isUniTranche,
30
31
  }: Props): React.ReactElement | null {
32
+ useLogOnFirstMount('ChooseAmount')
31
33
  const dispatch = useAppDispatch()
32
34
  const { symbol, decimals } = poolInfo.underlyingMint
33
35
  const [currentAmount, setCurrentAmount] = useState<number | string>(0)
@@ -8,12 +8,14 @@ import { WIDGET_STEP } from '../../../store/widgets.store'
8
8
  import { setStep } from '../../../store/widgets.reducers'
9
9
  import { BottomButton } from '../../BottomButton'
10
10
  import { AutoPaybackImg } from '../../images'
11
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
11
12
 
12
13
  type Props = {
13
14
  poolState: SolanaPoolState
14
15
  }
15
16
 
16
17
  export function ApproveAllowance({ poolState }: Props): React.ReactElement {
18
+ useLogOnFirstMount('ApproveAllowance')
17
19
  const theme = useTheme()
18
20
  const dispatch = useAppDispatch()
19
21
  const handleNext = useCallback(() => {
@@ -28,6 +28,7 @@ import { selectWidgetState } from '../../../store/widgets.selectors'
28
28
  import { WIDGET_STEP } from '../../../store/widgets.store'
29
29
  import { LoadingModal } from '../../LoadingModal'
30
30
  import { SolanaTxSendModal } from '../../SolanaTxSendModal'
31
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
31
32
 
32
33
  type Props = {
33
34
  poolInfo: SolanaPoolInfo
@@ -42,6 +43,7 @@ export function Transfer({
42
43
  selectedTranche,
43
44
  networkType,
44
45
  }: Props): React.ReactElement | null {
46
+ useLogOnFirstMount('Transaction')
45
47
  const isDev = checkIsDev()
46
48
  const dispatch = useAppDispatch()
47
49
  const { publicKey } = useWallet()
@@ -14,6 +14,7 @@ import { setStep } from '../../../store/widgets.reducers'
14
14
  import { selectWidgetState } from '../../../store/widgets.selectors'
15
15
  import { WIDGET_STEP } from '../../../store/widgets.store'
16
16
  import { SolanaTxDoneModal } from '../../SolanaTxDoneModal'
17
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
17
18
 
18
19
  type Props = {
19
20
  poolInfo: SolanaPoolInfo
@@ -28,6 +29,7 @@ export function Success({
28
29
  campaign,
29
30
  handleAction,
30
31
  }: Props): React.ReactElement {
32
+ useLogOnFirstMount('Success')
31
33
  const dispatch = useDispatch()
32
34
  const { supplyAmount, solanaSignature } = useAppSelector(selectWidgetState)
33
35
  const { symbol } = poolInfo.underlyingMint
@@ -22,6 +22,7 @@ import { BottomButton } from '../../BottomButton'
22
22
  import { CongratulationsIcon, HumaPointsIcon, RibbonIcon } from '../../icons'
23
23
  import { LoadingModal } from '../../LoadingModal'
24
24
  import { SignIn } from '../../SignIn'
25
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
25
26
 
26
27
  enum STATE {
27
28
  Loading = 'Loading',
@@ -42,6 +43,7 @@ export function PointsEarned({
42
43
  networkType,
43
44
  handleAction,
44
45
  }: Props): React.ReactElement {
46
+ useLogOnFirstMount('PointsEarned')
45
47
  const theme = useTheme()
46
48
  const isDev = checkIsDev()
47
49
  const dispatch = useDispatch()
@@ -5,6 +5,8 @@ import {
5
5
  TrancheType,
6
6
  } from '@huma-finance/shared'
7
7
  import {
8
+ LoggingContext,
9
+ LoggingContextHelper,
8
10
  SolanaPoolState,
9
11
  useLenderAccounts,
10
12
  useTokenAccount,
@@ -13,8 +15,11 @@ import React, { useEffect, useState } from 'react'
13
15
  import { useDispatch } from 'react-redux'
14
16
 
15
17
  import { useAppSelector } from '../../../hooks/useRedux'
16
- import { setStep } from '../../../store/widgets.reducers'
17
- import { selectWidgetState } from '../../../store/widgets.selectors'
18
+ import { setLoggingContext, setStep } from '../../../store/widgets.reducers'
19
+ import {
20
+ selectWidgetLoggingContext,
21
+ selectWidgetState,
22
+ } from '../../../store/widgets.selectors'
18
23
  import { WIDGET_STEP } from '../../../store/widgets.store'
19
24
  import { PointsEarned } from '../../PointsEarned'
20
25
  import { WidgetWrapper } from '../../WidgetWrapper'
@@ -65,33 +70,67 @@ export function SolanaLendSupply({
65
70
  } = useLenderAccounts(poolInfo.chainId, poolInfo.poolName)
66
71
  const [tokenAccount, isLoadingTokenAccount] = useTokenAccount(poolInfo)
67
72
  const { step, errorMessage } = useAppSelector(selectWidgetState)
73
+ const loggingHelper = useAppSelector(selectWidgetLoggingContext)
68
74
  const [selectedTranche, setSelectedTranche] = useState<TrancheType>()
69
75
 
76
+ const handleCloseFlow = () => {
77
+ loggingHelper.logAction('ExitFlow', {})
78
+ handleClose()
79
+ }
80
+
70
81
  useEffect(() => {
71
82
  if (!step && !isLoadingLenderAccounts && !isLoadingTokenAccount) {
83
+ // Set initial logging context
84
+ const context: LoggingContext = {
85
+ flow: 'Supply',
86
+ chainId: poolInfo.chainId,
87
+ poolName: poolInfo.poolName,
88
+ poolType: poolInfo.poolType,
89
+ }
90
+ const loggingHelperInit = new LoggingContextHelper(context)
91
+ loggingHelperInit.logAction('StartFlow', {})
92
+ dispatch(setLoggingContext(context))
93
+
72
94
  if (!juniorLenderApproved && !seniorLenderApproved) {
95
+ loggingHelperInit.logAction('SetInitialStep', {
96
+ step: WIDGET_STEP.Evaluation,
97
+ })
73
98
  dispatch(setStep(WIDGET_STEP.Evaluation))
74
99
  return
75
100
  }
76
101
 
77
102
  if (!isUniTranche && (!juniorLenderApproved || !seniorLenderApproved)) {
103
+ loggingHelperInit.logAction('SetInitialStep', {
104
+ step: WIDGET_STEP.ApproveLender,
105
+ })
78
106
  dispatch(setStep(WIDGET_STEP.ApproveLender))
79
107
  return
80
108
  }
81
109
 
82
110
  if (juniorLenderApproved && !seniorLenderApproved) {
111
+ loggingHelperInit.logAction('SetInitialStep', {
112
+ step: WIDGET_STEP.ChooseAmount,
113
+ tranche: 'junior',
114
+ })
83
115
  setSelectedTranche('junior')
84
116
  dispatch(setStep(WIDGET_STEP.ChooseAmount))
85
117
  return
86
118
  }
87
119
 
88
120
  if (seniorLenderApproved && !juniorLenderApproved) {
121
+ loggingHelperInit.logAction('SetInitialStep', {
122
+ step: WIDGET_STEP.ChooseAmount,
123
+ tranche: 'senior',
124
+ })
89
125
  setSelectedTranche('senior')
90
126
  dispatch(setStep(WIDGET_STEP.ChooseAmount))
91
127
  return
92
128
  }
93
129
 
94
130
  if (juniorLenderApproved && seniorLenderApproved) {
131
+ loggingHelperInit.logAction('SetInitialStep', {
132
+ step: WIDGET_STEP.ChooseTranche,
133
+ })
95
134
  dispatch(setStep(WIDGET_STEP.ChooseTranche))
96
135
  }
97
136
  }
@@ -113,7 +152,7 @@ export function SolanaLendSupply({
113
152
  isOpen
114
153
  isLoading
115
154
  loadingTitle='Supply'
116
- handleClose={handleClose}
155
+ handleClose={handleCloseFlow}
117
156
  handleSuccess={handleSuccess}
118
157
  />
119
158
  )
@@ -123,7 +162,7 @@ export function SolanaLendSupply({
123
162
  <WidgetWrapper
124
163
  isOpen
125
164
  loadingTitle={`Supply ${poolInfo.underlyingMint.symbol}`}
126
- handleClose={handleClose}
165
+ handleClose={handleCloseFlow}
127
166
  handleSuccess={handleSuccess}
128
167
  >
129
168
  {step === WIDGET_STEP.Evaluation && (
@@ -132,7 +171,7 @@ export function SolanaLendSupply({
132
171
  campaign={poolState.campaign}
133
172
  documentHash={documentHash}
134
173
  networkType={getSolanaNetworkType(poolInfo.chainId)}
135
- handleClose={handleClose}
174
+ handleClose={handleCloseFlow}
136
175
  />
137
176
  )}
138
177
  {step === WIDGET_STEP.ApproveLender && (
@@ -175,11 +214,11 @@ export function SolanaLendSupply({
175
214
  poolInfo={poolInfo}
176
215
  poolState={poolState}
177
216
  campaign={poolState.campaign}
178
- handleAction={handleClose}
217
+ handleAction={handleCloseFlow}
179
218
  />
180
219
  )}
181
220
  {step === WIDGET_STEP.PointsEarned && (
182
- <PointsEarned lpConfig={poolState} handleAction={handleClose} />
221
+ <PointsEarned lpConfig={poolState} handleAction={handleCloseFlow} />
183
222
  )}
184
223
  {step === WIDGET_STEP.Error && (
185
224
  <SolanaErrorModal
@@ -187,7 +226,7 @@ export function SolanaLendSupply({
187
226
  title='Supply'
188
227
  errorReason='Sorry there was an error'
189
228
  errorMessage={errorMessage}
190
- handleOk={handleClose}
229
+ handleOk={handleCloseFlow}
191
230
  />
192
231
  )}
193
232
  </WidgetWrapper>
@@ -6,6 +6,7 @@ import { setStep } from '../../../store/widgets.reducers'
6
6
  import { WIDGET_STEP } from '../../../store/widgets.store'
7
7
  import { BottomButton } from '../../BottomButton'
8
8
  import { WrapperModal } from '../../WrapperModal'
9
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
9
10
 
10
11
  type Props = {
11
12
  poolUnderlyingToken: UnderlyingTokenInfo
@@ -18,6 +19,7 @@ export function ConfirmTransfer({
18
19
  withdrawableAmountFormatted,
19
20
  sharePrice,
20
21
  }: Props): React.ReactElement {
22
+ useLogOnFirstMount('ConfirmTransfer')
21
23
  const theme = useTheme()
22
24
  const dispatch = useDispatch()
23
25
  const { symbol } = poolUnderlyingToken
@@ -12,6 +12,7 @@ import { useAppDispatch } from '../../../hooks/useRedux'
12
12
  import { setStep } from '../../../store/widgets.reducers'
13
13
  import { WIDGET_STEP } from '../../../store/widgets.store'
14
14
  import { SolanaTxSendModal } from '../../SolanaTxSendModal'
15
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
15
16
 
16
17
  type Props = {
17
18
  poolInfo: SolanaPoolInfo
@@ -24,6 +25,7 @@ export function Transfer({
24
25
  selectedTranche,
25
26
  poolIsClosed,
26
27
  }: Props): React.ReactElement | null {
28
+ useLogOnFirstMount('Transaction')
27
29
  const { publicKey } = useWallet()
28
30
  const dispatch = useAppDispatch()
29
31
  const program = useHumaProgram(poolInfo.chainId)
@@ -6,6 +6,7 @@ import {
6
6
  } from '@huma-finance/shared'
7
7
  import React from 'react'
8
8
  import { TxDoneModal } from '../../TxDoneModal'
9
+ import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
9
10
 
10
11
  type Props = {
11
12
  poolUnderlyingToken: UnderlyingTokenInfo
@@ -18,6 +19,7 @@ export function Done({
18
19
  withdrawAmount,
19
20
  handleAction,
20
21
  }: Props): React.ReactElement {
22
+ useLogOnFirstMount('Success')
21
23
  const { symbol } = poolUnderlyingToken
22
24
  const withdrawAmountFormatted = formatMoneyFixed(
23
25
  SolanaTokenUtils.formatUnits(withdrawAmount, poolUnderlyingToken.decimals),
@@ -4,15 +4,23 @@ import {
4
4
  SolanaTokenUtils,
5
5
  TrancheType,
6
6
  } from '@huma-finance/shared'
7
- import { LenderStateAccount, SolanaPoolState } from '@huma-finance/web-shared'
7
+ import {
8
+ LenderStateAccount,
9
+ LoggingContext,
10
+ LoggingContextHelper,
11
+ SolanaPoolState,
12
+ } from '@huma-finance/web-shared'
8
13
  import React, { useCallback, useEffect, useState } from 'react'
9
14
  import { useDispatch } from 'react-redux'
10
15
 
11
16
  import { BN } from '@coral-xyz/anchor'
12
17
  import { Mint } from '@solana/spl-token'
13
18
  import { useAppSelector } from '../../../hooks/useRedux'
14
- import { setStep } from '../../../store/widgets.reducers'
15
- import { selectWidgetState } from '../../../store/widgets.selectors'
19
+ import { setLoggingContext, setStep } from '../../../store/widgets.reducers'
20
+ import {
21
+ selectWidgetLoggingContext,
22
+ selectWidgetState,
23
+ } from '../../../store/widgets.selectors'
16
24
  import { WIDGET_STEP } from '../../../store/widgets.store'
17
25
  import { ErrorModal } from '../../ErrorModal'
18
26
  import { WidgetWrapper } from '../../WidgetWrapper'
@@ -64,6 +72,12 @@ export function SolanaLendWithdraw({
64
72
  2,
65
73
  )
66
74
  const [withdrawnAmount, setWithdrawnAmount] = useState<BN>()
75
+ const loggingHelper = useAppSelector(selectWidgetLoggingContext)
76
+
77
+ const handleCloseFlow = () => {
78
+ loggingHelper.logAction('ExitFlow', {})
79
+ handleClose()
80
+ }
67
81
 
68
82
  // After withdrawn success, the handleSuccess will refresh
69
83
  // the lenderStateAccount which will update the withdrawableAmount to 0
@@ -76,9 +90,20 @@ export function SolanaLendWithdraw({
76
90
 
77
91
  useEffect(() => {
78
92
  if (!step) {
93
+ // Set initial logging context
94
+ const context: LoggingContext = {
95
+ flow: 'Withdraw',
96
+ chainId: poolInfo.chainId,
97
+ poolName: poolInfo.poolName,
98
+ poolType: poolInfo.poolType,
99
+ }
100
+ const loggingHelperInit = new LoggingContextHelper(context)
101
+ loggingHelperInit.logAction('StartFlow', {})
102
+ dispatch(setLoggingContext(context))
103
+
79
104
  dispatch(setStep(WIDGET_STEP.ConfirmTransfer))
80
105
  }
81
- }, [dispatch, step])
106
+ }, [dispatch, poolInfo.chainId, poolInfo.poolName, poolInfo.poolType, step])
82
107
 
83
108
  useEffect(() => {
84
109
  const trancheAssets =
@@ -111,7 +136,7 @@ export function SolanaLendWithdraw({
111
136
  <WidgetWrapper
112
137
  isOpen
113
138
  loadingTitle={title}
114
- handleClose={handleClose}
139
+ handleClose={handleCloseFlow}
115
140
  handleSuccess={handleWithdrawSuccess}
116
141
  >
117
142
  {step === WIDGET_STEP.ConfirmTransfer && (
@@ -132,7 +157,7 @@ export function SolanaLendWithdraw({
132
157
  <Done
133
158
  poolUnderlyingToken={poolInfo.underlyingMint}
134
159
  withdrawAmount={withdrawnAmount}
135
- handleAction={handleClose}
160
+ handleAction={handleCloseFlow}
136
161
  />
137
162
  )}
138
163
  {step === WIDGET_STEP.Error && (
@@ -140,7 +165,7 @@ export function SolanaLendWithdraw({
140
165
  title={title}
141
166
  errorReason='Sorry there was an error'
142
167
  errorMessage={errorMessage}
143
- handleOk={handleClose}
168
+ handleOk={handleCloseFlow}
144
169
  />
145
170
  )}
146
171
  </WidgetWrapper>
@@ -9,11 +9,12 @@ import { useConnection, useWallet } from '@solana/wallet-adapter-react'
9
9
  import { Transaction } from '@solana/web3.js'
10
10
  import { useForceRefresh } from '@huma-finance/web-shared'
11
11
  import { Box, Button, css, Typography, useTheme } from '@mui/material'
12
- import { useAppDispatch } from '../hooks/useRedux'
12
+ import { useAppDispatch, useAppSelector } from '../hooks/useRedux'
13
13
  import { setError, setSolanaSignature } from '../store/widgets.reducers'
14
14
  import { LoadingModal } from './LoadingModal'
15
15
  import { SolanaViewOnExplorer } from './SolanaViewOnExplorer'
16
16
  import { SorryImg } from './images'
17
+ import { selectWidgetLoggingContext } from '../store/widgets.selectors'
17
18
 
18
19
  type Props = {
19
20
  chainId: SolanaChainEnum
@@ -33,6 +34,7 @@ export function SolanaTxSendModal({
33
34
  const [signature, setSignature] = useState<string>('')
34
35
  const [showRetryScreen, setShowRetryScreen] = useState<boolean>(false)
35
36
  const [useHighPriority, setUseHighPriority] = useState<boolean>(true)
37
+ const loggingHelper = useAppSelector(selectWidgetLoggingContext)
36
38
  const [refreshCount, refresh] = useForceRefresh()
37
39
 
38
40
  const styles = {
@@ -98,7 +100,14 @@ export function SolanaTxSendModal({
98
100
  useHighPriority ? 'High' : undefined,
99
101
  process.env.REACT_APP_HELIUS_API_KEY,
100
102
  )
103
+ loggingHelper.logAction('SigningTransaction', {
104
+ priceData: optimizedTx.instructions[0].data,
105
+ unitsData: optimizedTx.instructions[1].data,
106
+ recentBlockhash: optimizedTx.recentBlockhash,
107
+ lastValidBlockHeight: optimizedTx.lastValidBlockHeight,
108
+ })
101
109
  const signedTx = await signTransaction(optimizedTx)
110
+ loggingHelper.logAction('SendingTransaction', {})
102
111
  const signatureResult = await connection.sendRawTransaction(
103
112
  signedTx.serialize(),
104
113
  {
@@ -123,6 +132,9 @@ export function SolanaTxSendModal({
123
132
  result?.value?.confirmationStatus === 'confirmed'
124
133
  ) {
125
134
  if (result?.value?.err) {
135
+ loggingHelper.logAction('TransactionError', {
136
+ signature: signatureResult,
137
+ })
126
138
  dispatch(
127
139
  setError({
128
140
  errorMessage:
@@ -131,6 +143,10 @@ export function SolanaTxSendModal({
131
143
  )
132
144
  return
133
145
  }
146
+
147
+ loggingHelper.logAction('TransactionSuccess', {
148
+ signature: signatureResult,
149
+ })
134
150
  handleSuccess({ signature: signatureResult })
135
151
  return
136
152
  }
@@ -144,6 +160,9 @@ export function SolanaTxSendModal({
144
160
  optimizedTx.lastValidBlockHeight! >
145
161
  100
146
162
  ) {
163
+ loggingHelper.logAction('ShowRetryScreenDueToExpiration', {
164
+ signature: signatureResult,
165
+ })
147
166
  setShowRetryScreen(true)
148
167
  return
149
168
  }
@@ -155,6 +174,8 @@ export function SolanaTxSendModal({
155
174
  console.log(error)
156
175
 
157
176
  const err = error as Error
177
+ loggingHelper.logAction('UnknownError', { error: err?.message })
178
+ loggingHelper.logError(err)
158
179
  dispatch(setError({ errorMessage: err?.message || '' }))
159
180
  }
160
181
  }
@@ -170,6 +191,7 @@ export function SolanaTxSendModal({
170
191
  tx,
171
192
  refreshCount,
172
193
  useHighPriority,
194
+ loggingHelper,
173
195
  ])
174
196
 
175
197
  const handleRetry = useCallback(
@@ -0,0 +1,19 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { LoggingActions } from '@huma-finance/web-shared'
3
+ import { selectWidgetLoggingContext } from '../store/widgets.selectors'
4
+ import { useAppSelector } from './useRedux'
5
+
6
+ const useLogOnFirstMount = (action: LoggingActions, data: object = {}) => {
7
+ const loggingHelper = useAppSelector(selectWidgetLoggingContext)
8
+ const hasLogged = useRef(false)
9
+
10
+ useEffect(() => {
11
+ // Only log the action once
12
+ if (!hasLogged.current) {
13
+ loggingHelper.logAction(action, data)
14
+ hasLogged.current = true
15
+ }
16
+ }, [action, data, loggingHelper])
17
+ }
18
+
19
+ export default useLogOnFirstMount
@@ -1,5 +1,6 @@
1
1
  import { Approval } from '@huma-finance/shared'
2
2
  import { createSlice, PayloadAction } from '@reduxjs/toolkit'
3
+ import { LoggingContext } from '@huma-finance/web-shared'
3
4
 
4
5
  import {
5
6
  initialWidgetState,
@@ -34,6 +35,7 @@ export const widgetSlice = createSlice({
34
35
  state.redeemShares = undefined
35
36
  state.solanaSignature = undefined
36
37
  state.txHash = undefined
38
+ state.loggingContext = undefined
37
39
  },
38
40
  setStep: (state, { payload }: PayloadAction<WIDGET_STEP>) => {
39
41
  state.step = payload
@@ -116,6 +118,9 @@ export const widgetSlice = createSlice({
116
118
  ) => {
117
119
  state.pointsAccumulated = payload
118
120
  },
121
+ setLoggingContext: (state, { payload }: PayloadAction<LoggingContext>) => {
122
+ state.loggingContext = payload
123
+ },
119
124
  setError: (
120
125
  state,
121
126
  {
@@ -147,6 +152,7 @@ export const {
147
152
  setSolanaSignature,
148
153
  setTxHash,
149
154
  setPointsAccumulated,
155
+ setLoggingContext,
150
156
  } = widgetSlice.actions
151
157
 
152
158
  export default widgetSlice.reducer
@@ -1,3 +1,23 @@
1
+ import { LoggingContextHelper } from '@huma-finance/web-shared'
1
2
  import { RootState } from '.'
2
3
 
3
4
  export const selectWidgetState = (state: RootState) => state.widget
5
+
6
+ let cachedContext: LoggingContextHelper | null = null
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ let cachedLoggingContext: any = null
9
+
10
+ export const selectWidgetLoggingContext = (
11
+ state: RootState,
12
+ ): LoggingContextHelper => {
13
+ if (state.widget.loggingContext === cachedLoggingContext) {
14
+ return cachedContext!
15
+ }
16
+
17
+ cachedLoggingContext = state.widget.loggingContext
18
+ cachedContext = state.widget.loggingContext
19
+ ? new LoggingContextHelper(state.widget.loggingContext)
20
+ : new LoggingContextHelper()
21
+
22
+ return cachedContext
23
+ }