@huma-finance/widgets 0.0.62-beta.622 → 0.0.62-beta.627

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huma-finance/widgets",
3
- "version": "0.0.62-beta.622+137e1dc",
3
+ "version": "0.0.62-beta.627+ed48d14",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -28,9 +28,9 @@
28
28
  "@ethersproject/experimental": "^5.7.0",
29
29
  "@ethersproject/providers": "^5.6.0",
30
30
  "@ethersproject/units": "^5.6.0",
31
- "@huma-finance/sdk": "^0.0.62-beta.622+137e1dc",
32
- "@huma-finance/shared": "^0.0.62-beta.622+137e1dc",
33
- "@huma-finance/web-shared": "^0.0.61",
31
+ "@huma-finance/sdk": "^0.0.62-beta.627+ed48d14",
32
+ "@huma-finance/shared": "^0.0.62-beta.627+ed48d14",
33
+ "@huma-finance/web-shared": "^0.0.62-beta.627+ed48d14",
34
34
  "@notifi-network/notifi-frontend-client": "^0.91.1",
35
35
  "@reduxjs/toolkit": "^1.8.6",
36
36
  "@types/utf8": "^3.0.1",
@@ -200,5 +200,5 @@
200
200
  "optionalDependencies": {
201
201
  "encoding": "^0.1.13"
202
202
  },
203
- "gitHead": "137e1dc3d62ae552c1f93c6c489440ccc0e569d7"
203
+ "gitHead": "ed48d14997b960c2036daba1b6f303fcda551c26"
204
204
  }
@@ -45,6 +45,7 @@ export function ChooseAmount({
45
45
  ethers.utils.formatUnits(payoffAmountBN, decimals),
46
46
  )
47
47
 
48
+ // TODO: Remove redundant useEffect
48
49
  useEffect(() => {
49
50
  setCurrentAmount(totalDueAmount)
50
51
  }, [totalDueAmount])
@@ -1,14 +1,11 @@
1
1
  import {
2
2
  formatNumber,
3
- getSentinelAddress,
4
3
  SolanaPoolInfo,
5
4
  SolanaTokenUtils,
6
5
  } from '@huma-finance/shared'
7
6
  import { CreditConfigAccount } from '@huma-finance/web-shared'
8
7
  import React, { useCallback, useMemo, useState } from 'react'
9
8
 
10
- import { BN } from '@coral-xyz/anchor'
11
- import { Account } from '@solana/spl-token'
12
9
  import { useAppDispatch } from '../../../hooks/useRedux'
13
10
  import { setBorrowInfo } from '../../../store/widgets.reducers'
14
11
  import { WIDGET_STEP } from '../../../store/widgets.store'
@@ -17,20 +14,14 @@ import { InputAmountModal } from '../../InputAmountModal'
17
14
  type Props = {
18
15
  poolInfo: SolanaPoolInfo
19
16
  creditConfigAccount: CreditConfigAccount
20
- tokenAccount: Account
21
17
  }
22
18
 
23
19
  export function ChooseAmount({
24
20
  poolInfo,
25
21
  creditConfigAccount,
26
- tokenAccount,
27
22
  }: Props): React.ReactElement {
28
23
  const dispatch = useAppDispatch()
29
24
  const { symbol, decimals } = poolInfo.underlyingMint
30
- const sentinel = useMemo(
31
- () => getSentinelAddress(poolInfo.chainId),
32
- [poolInfo.chainId],
33
- )
34
25
  const [currentAmount, setCurrentAmount] = useState<number>(0)
35
26
  const creditAvailable = useMemo(
36
27
  () =>
@@ -46,29 +37,19 @@ export function ChooseAmount({
46
37
  }
47
38
 
48
39
  const handleAction = useCallback(() => {
49
- if (!tokenAccount) {
50
- return
51
- }
52
-
53
40
  const borrowAmountBN = SolanaTokenUtils.parseUnits(
54
41
  String(currentAmount),
55
42
  decimals,
56
43
  )
57
- const nextStep =
58
- borrowAmountBN.gt(new BN(tokenAccount.delegatedAmount.toString())) ||
59
- tokenAccount.delegate?.toString() !== sentinel
60
- ? WIDGET_STEP.ApproveAllowance
61
- : WIDGET_STEP.Transfer
62
-
63
44
  dispatch(
64
45
  setBorrowInfo({
65
46
  borrowAmount: currentAmount,
66
47
  borrowAmountBN: JSON.parse(borrowAmountBN.toString()),
67
48
  chargedFees: 0,
68
- nextStep,
49
+ nextStep: WIDGET_STEP.Transfer,
69
50
  }),
70
51
  )
71
- }, [currentAmount, decimals, dispatch, sentinel, tokenAccount])
52
+ }, [currentAmount, decimals, dispatch])
72
53
 
73
54
  return (
74
55
  <InputAmountModal
@@ -0,0 +1,159 @@
1
+ import {
2
+ getCreditAccounts,
3
+ getSentinelAddress,
4
+ getTokenAccounts,
5
+ SolanaPoolInfo,
6
+ SolanaTokenUtils,
7
+ } from '@huma-finance/shared'
8
+ import React, { useCallback, useEffect, useState } from 'react'
9
+
10
+ import {
11
+ ASSOCIATED_TOKEN_PROGRAM_ID,
12
+ createApproveCheckedInstruction,
13
+ createAssociatedTokenAccountInstruction,
14
+ getAccount,
15
+ TOKEN_2022_PROGRAM_ID,
16
+ TokenAccountNotFoundError,
17
+ TokenInvalidAccountOwnerError,
18
+ } from '@solana/spl-token'
19
+ import { useConnection, useWallet } from '@solana/wallet-adapter-react'
20
+ import { PublicKey, Transaction } from '@solana/web3.js'
21
+ import { useHumaProgram } from '@huma-finance/web-shared'
22
+ import { BN } from '@coral-xyz/anchor'
23
+ import { useAppDispatch, useAppSelector } from '../../../hooks/useRedux'
24
+ import { SolanaTxSendModal } from '../../SolanaTxSendModal'
25
+ import { setStep } from '../../../store/widgets.reducers'
26
+ import { WIDGET_STEP } from '../../../store/widgets.store'
27
+ import { selectWidgetState } from '../../../store/widgets.selectors'
28
+
29
+ type Props = {
30
+ poolInfo: SolanaPoolInfo
31
+ }
32
+
33
+ export function Transfer({ poolInfo }: Props): React.ReactElement | null {
34
+ const dispatch = useAppDispatch()
35
+ const { wallet, publicKey } = useWallet()
36
+ const sentinel = getSentinelAddress(poolInfo.chainId)
37
+ const { connection } = useConnection()
38
+ const [transaction, setTransaction] = useState<Transaction>()
39
+ const program = useHumaProgram(poolInfo.chainId)
40
+ const { borrowAmountBN: borrowAmountBNJson } =
41
+ useAppSelector(selectWidgetState)
42
+
43
+ const handleSuccess = useCallback(() => {
44
+ dispatch(setStep(WIDGET_STEP.Done))
45
+ }, [dispatch])
46
+
47
+ useEffect(() => {
48
+ async function getTx() {
49
+ if (!wallet || !publicKey || !connection) {
50
+ return
51
+ }
52
+
53
+ const { underlyingTokenATA } = getTokenAccounts(poolInfo, publicKey)
54
+ const tx = new Transaction()
55
+
56
+ // Create user token account if it doesn't exist
57
+ let tokenAccount
58
+ try {
59
+ tokenAccount = await getAccount(
60
+ connection,
61
+ underlyingTokenATA,
62
+ undefined,
63
+ TOKEN_2022_PROGRAM_ID,
64
+ )
65
+ } catch (error: unknown) {
66
+ // TokenAccountNotFoundError can be possible if the associated address has already received some lamports,
67
+ // becoming a system account. Assuming program derived addressing is safe, this is the only case for the
68
+ // TokenInvalidAccountOwnerError in this code path.
69
+ if (
70
+ error instanceof TokenAccountNotFoundError ||
71
+ error instanceof TokenInvalidAccountOwnerError
72
+ ) {
73
+ // As this isn't atomic, it's possible others can create associated accounts meanwhile.
74
+ tx.add(
75
+ createAssociatedTokenAccountInstruction(
76
+ publicKey,
77
+ underlyingTokenATA,
78
+ publicKey,
79
+ new PublicKey(poolInfo.underlyingMint.address),
80
+ TOKEN_2022_PROGRAM_ID,
81
+ ASSOCIATED_TOKEN_PROGRAM_ID,
82
+ ),
83
+ )
84
+ }
85
+ }
86
+
87
+ // Approve allowance to the sentinel if the account is new or delegated amount is not enough
88
+ const borrowAmountBN = new BN(borrowAmountBNJson?.toString() ?? '0')
89
+ if (
90
+ !tokenAccount ||
91
+ borrowAmountBN.gt(new BN(tokenAccount.delegatedAmount.toString())) ||
92
+ tokenAccount.delegate?.toString() !== sentinel
93
+ ) {
94
+ tx.add(
95
+ createApproveCheckedInstruction(
96
+ underlyingTokenATA,
97
+ new PublicKey(poolInfo.underlyingMint.address),
98
+ new PublicKey(sentinel), // delegate
99
+ publicKey, // owner of the wallet
100
+ BigInt(
101
+ SolanaTokenUtils.parseUnits(
102
+ '100000000000', // 100 billion
103
+ poolInfo.underlyingMint.decimals,
104
+ ).toString(),
105
+ ), // amount
106
+ poolInfo.underlyingMint.decimals,
107
+ undefined, // multiSigners
108
+ TOKEN_2022_PROGRAM_ID,
109
+ ),
110
+ )
111
+ }
112
+
113
+ const { creditConfigAccount, creditStateAccount } = getCreditAccounts(
114
+ poolInfo,
115
+ publicKey,
116
+ )
117
+ // borrowAmountBNJson is stored as a raw number string in this flow
118
+ const programTx = await program.methods
119
+ .drawdown(borrowAmountBN)
120
+ .accountsPartial({
121
+ borrower: publicKey,
122
+ humaConfig: poolInfo.humaConfig,
123
+ poolConfig: poolInfo.poolConfig,
124
+ poolState: poolInfo.poolState,
125
+ creditConfig: creditConfigAccount,
126
+ creditState: creditStateAccount,
127
+ poolAuthority: poolInfo.poolAuthority,
128
+ underlyingMint: poolInfo.underlyingMint.address,
129
+ poolUnderlyingToken: poolInfo.poolUnderlyingTokenAccount,
130
+ borrowerUnderlyingToken: underlyingTokenATA,
131
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
132
+ })
133
+ .transaction()
134
+ tx.add(programTx)
135
+
136
+ setTransaction(tx)
137
+ }
138
+ getTx()
139
+ }, [
140
+ borrowAmountBNJson,
141
+ connection,
142
+ dispatch,
143
+ poolInfo,
144
+ poolInfo.underlyingMint.address,
145
+ poolInfo.underlyingMint.decimals,
146
+ program.methods,
147
+ publicKey,
148
+ sentinel,
149
+ wallet,
150
+ ])
151
+
152
+ return (
153
+ <SolanaTxSendModal
154
+ tx={transaction}
155
+ chainId={poolInfo.chainId}
156
+ handleSuccess={handleSuccess}
157
+ />
158
+ )
159
+ }
@@ -0,0 +1,38 @@
1
+ import { formatNumber, SolanaPoolInfo, timeUtil } from '@huma-finance/shared'
2
+ import React from 'react'
3
+
4
+ import { SolanaPoolState } from '@huma-finance/web-shared'
5
+ import { useAppSelector } from '../../../hooks/useRedux'
6
+ import { selectWidgetState } from '../../../store/widgets.selectors'
7
+ import { SolanaTxDoneModal } from '../../SolanaTxDoneModal'
8
+
9
+ type Props = {
10
+ poolInfo: SolanaPoolInfo
11
+ poolState: SolanaPoolState
12
+ handleAction: () => void
13
+ }
14
+
15
+ export function Done({
16
+ poolInfo,
17
+ poolState,
18
+ handleAction,
19
+ }: Props): React.ReactElement {
20
+ const { borrowAmount, solanaSignature } = useAppSelector(selectWidgetState)
21
+ const { symbol } = poolInfo.underlyingMint
22
+ const dueDate = timeUtil.timestampToLL(poolState.epochEndTime)
23
+
24
+ const content = [
25
+ `${formatNumber(borrowAmount)} ${symbol} is now in your wallet.`,
26
+ `Note: your first automatic payment will occur after ${dueDate}.`,
27
+ ]
28
+
29
+ return (
30
+ <SolanaTxDoneModal
31
+ handleAction={handleAction}
32
+ content={content}
33
+ chainId={poolInfo.chainId}
34
+ solanaSignature={solanaSignature}
35
+ buttonText='DONE'
36
+ />
37
+ )
38
+ }
@@ -1,8 +1,5 @@
1
1
  import { SolanaPoolInfo } from '@huma-finance/shared'
2
- import {
3
- useBorrowerAccounts,
4
- usePoolUnderlyingTokenAccount,
5
- } from '@huma-finance/web-shared'
2
+ import { SolanaPoolState, useBorrowerAccounts } from '@huma-finance/web-shared'
6
3
  import React, { useEffect } from 'react'
7
4
  import { useDispatch } from 'react-redux'
8
5
 
@@ -13,7 +10,8 @@ import { WIDGET_STEP } from '../../../store/widgets.store'
13
10
  import { setStep } from '../../../store/widgets.reducers'
14
11
  import { ErrorModal } from '../../ErrorModal'
15
12
  import { ChooseAmount } from './1-ChooseAmount'
16
- import { ApproveAllowance } from './2-ApproveAllowance'
13
+ import { Transfer } from './2-Transfer'
14
+ import { Done } from './3-Done'
17
15
 
18
16
  /**
19
17
  * Lend pool supply props
@@ -24,20 +22,20 @@ import { ApproveAllowance } from './2-ApproveAllowance'
24
22
  */
25
23
  export interface SolanaBorrowProps {
26
24
  poolInfo: SolanaPoolInfo
25
+ poolState: SolanaPoolState
27
26
  handleClose: () => void
28
27
  handleSuccess?: () => void
29
28
  }
30
29
 
31
30
  export function SolanaBorrow({
32
31
  poolInfo,
32
+ poolState,
33
33
  handleClose,
34
34
  handleSuccess,
35
35
  }: SolanaBorrowProps): React.ReactElement | null {
36
36
  const dispatch = useDispatch()
37
37
  const { creditConfigAccount, loading: isLoadingBorrowerAccounts } =
38
38
  useBorrowerAccounts(poolInfo.chainId, poolInfo.poolName)
39
- const { account: tokenAccount, loading: isLoadingTokenAccounts } =
40
- usePoolUnderlyingTokenAccount(poolInfo)
41
39
  const { step, errorMessage } = useAppSelector(selectWidgetState)
42
40
  useEffect(() => {
43
41
  if (!step) {
@@ -45,8 +43,8 @@ export function SolanaBorrow({
45
43
  }
46
44
  }, [dispatch, step])
47
45
 
48
- const title = 'Redemption'
49
- if (isLoadingBorrowerAccounts || isLoadingTokenAccounts) {
46
+ const title = 'Borrow'
47
+ if (isLoadingBorrowerAccounts) {
50
48
  return (
51
49
  <WidgetWrapper
52
50
  isOpen
@@ -65,24 +63,20 @@ export function SolanaBorrow({
65
63
  handleClose={handleClose}
66
64
  handleSuccess={handleSuccess}
67
65
  >
68
- {step === WIDGET_STEP.ChooseAmount &&
69
- creditConfigAccount &&
70
- tokenAccount && (
71
- <ChooseAmount
72
- poolInfo={poolInfo}
73
- creditConfigAccount={creditConfigAccount}
74
- tokenAccount={tokenAccount}
75
- />
76
- )}
77
- {step === WIDGET_STEP.ApproveAllowance && tokenAccount && (
78
- <ApproveAllowance poolInfo={poolInfo} tokenAccount={tokenAccount} />
79
- )}
80
- {/* {step === WIDGET_STEP.Transfer && selectedTranche && (
81
- <Transfer poolInfo={poolInfo} selectedTranche={selectedTranche} />
66
+ {step === WIDGET_STEP.ChooseAmount && creditConfigAccount && (
67
+ <ChooseAmount
68
+ poolInfo={poolInfo}
69
+ creditConfigAccount={creditConfigAccount}
70
+ />
82
71
  )}
72
+ {step === WIDGET_STEP.Transfer && <Transfer poolInfo={poolInfo} />}
83
73
  {step === WIDGET_STEP.Done && (
84
- <Done poolInfo={poolInfo} handleAction={handleClose} />
85
- )} */}
74
+ <Done
75
+ poolInfo={poolInfo}
76
+ poolState={poolState}
77
+ handleAction={handleClose}
78
+ />
79
+ )}
86
80
  {step === WIDGET_STEP.Error && (
87
81
  <ErrorModal
88
82
  title={title}
@@ -0,0 +1,75 @@
1
+ import {
2
+ formatNumber,
3
+ SolanaPoolInfo,
4
+ SolanaTokenUtils,
5
+ } from '@huma-finance/shared'
6
+ import { CreditStateAccount } from '@huma-finance/web-shared'
7
+ import React, { useCallback, useEffect, useMemo, useState } from 'react'
8
+
9
+ import { useAppDispatch } from '../../../hooks/useRedux'
10
+ import { setPaymentAmount, setStep } from '../../../store/widgets.reducers'
11
+ import { WIDGET_STEP } from '../../../store/widgets.store'
12
+ import { InputAmountModal } from '../../InputAmountModal'
13
+
14
+ type Props = {
15
+ poolInfo: SolanaPoolInfo
16
+ creditStateAccount: CreditStateAccount
17
+ }
18
+
19
+ export function ChooseAmount({
20
+ poolInfo,
21
+ creditStateAccount,
22
+ }: Props): React.ReactElement {
23
+ const dispatch = useAppDispatch()
24
+ const { symbol, decimals } = poolInfo.underlyingMint
25
+ const [currentAmount, setCurrentAmount] = useState<number>(0)
26
+ const totalDueAmount = useMemo(
27
+ () =>
28
+ Number(
29
+ SolanaTokenUtils.formatUnits(
30
+ creditStateAccount.creditRecord.totalDueAmount,
31
+ decimals,
32
+ ),
33
+ ),
34
+ [creditStateAccount.creditRecord.totalDueAmount, decimals],
35
+ )
36
+ const payoffAmount = useMemo(
37
+ () =>
38
+ Number(
39
+ SolanaTokenUtils.formatUnits(
40
+ creditStateAccount.creditRecord.payoffAmount,
41
+ decimals,
42
+ ),
43
+ ),
44
+ [creditStateAccount.creditRecord.payoffAmount, decimals],
45
+ )
46
+
47
+ useEffect(() => {
48
+ setCurrentAmount(totalDueAmount)
49
+ dispatch(setPaymentAmount({ paymentAmount: totalDueAmount }))
50
+ }, [dispatch, totalDueAmount])
51
+
52
+ const handleChangeAmount = (newAmount: number) => {
53
+ setCurrentAmount(newAmount)
54
+ dispatch(setPaymentAmount({ paymentAmount: newAmount }))
55
+ }
56
+
57
+ const handleAction = useCallback(() => {
58
+ dispatch(setStep(WIDGET_STEP.Transfer))
59
+ }, [dispatch])
60
+
61
+ return (
62
+ <InputAmountModal
63
+ title='Make Payment'
64
+ subTitle='Choose Amount'
65
+ tokenSymbol={symbol}
66
+ currentAmount={currentAmount}
67
+ handleChangeAmount={handleChangeAmount}
68
+ maxAmount={payoffAmount}
69
+ maxAmountText='Pay Off'
70
+ infos={[`${formatNumber(totalDueAmount.toFixed(0))} Due`]}
71
+ handleAction={handleAction}
72
+ actionText='PAY'
73
+ />
74
+ )
75
+ }
@@ -0,0 +1,92 @@
1
+ import {
2
+ getCreditAccounts,
3
+ getTokenAccounts,
4
+ SolanaPoolInfo,
5
+ SolanaTokenUtils,
6
+ } from '@huma-finance/shared'
7
+ import React, { useCallback, useEffect, useState } from 'react'
8
+
9
+ import { TOKEN_2022_PROGRAM_ID } from '@solana/spl-token'
10
+ import { useConnection, useWallet } from '@solana/wallet-adapter-react'
11
+ import { Transaction } from '@solana/web3.js'
12
+ import { useHumaProgram } from '@huma-finance/web-shared'
13
+ import { useAppDispatch, useAppSelector } from '../../../hooks/useRedux'
14
+ import { SolanaTxSendModal } from '../../SolanaTxSendModal'
15
+ import { setStep } from '../../../store/widgets.reducers'
16
+ import { WIDGET_STEP } from '../../../store/widgets.store'
17
+ import { selectWidgetState } from '../../../store/widgets.selectors'
18
+
19
+ type Props = {
20
+ poolInfo: SolanaPoolInfo
21
+ }
22
+
23
+ export function Transfer({ poolInfo }: Props): React.ReactElement | null {
24
+ const dispatch = useAppDispatch()
25
+ const { wallet, publicKey } = useWallet()
26
+ const { connection } = useConnection()
27
+ const [transaction, setTransaction] = useState<Transaction>()
28
+ const program = useHumaProgram(poolInfo.chainId)
29
+ const { paymentAmount } = useAppSelector(selectWidgetState)
30
+ const { decimals } = poolInfo.underlyingMint
31
+
32
+ const handleSuccess = useCallback(() => {
33
+ dispatch(setStep(WIDGET_STEP.Done))
34
+ }, [dispatch])
35
+
36
+ useEffect(() => {
37
+ async function getTx() {
38
+ if (!wallet || !publicKey || !connection || !paymentAmount) {
39
+ return
40
+ }
41
+
42
+ const { underlyingTokenATA } = getTokenAccounts(poolInfo, publicKey)
43
+
44
+ const { creditConfigAccount, creditStateAccount } = getCreditAccounts(
45
+ poolInfo,
46
+ publicKey,
47
+ )
48
+ const paymentAmountBN = SolanaTokenUtils.parseUnits(
49
+ paymentAmount.toString(),
50
+ decimals,
51
+ )
52
+ const tx = await program.methods
53
+ .makePayment(paymentAmountBN)
54
+ .accountsPartial({
55
+ signer: publicKey,
56
+ humaConfig: poolInfo.humaConfig,
57
+ poolConfig: poolInfo.poolConfig,
58
+ poolState: poolInfo.poolState,
59
+ creditConfig: creditConfigAccount,
60
+ creditState: creditStateAccount,
61
+ poolAuthority: poolInfo.poolAuthority,
62
+ underlyingMint: poolInfo.underlyingMint.address,
63
+ poolUnderlyingToken: poolInfo.poolUnderlyingTokenAccount,
64
+ borrowerUnderlyingToken: underlyingTokenATA,
65
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
66
+ })
67
+ .transaction()
68
+
69
+ setTransaction(tx)
70
+ }
71
+ getTx()
72
+ }, [
73
+ connection,
74
+ decimals,
75
+ dispatch,
76
+ paymentAmount,
77
+ poolInfo,
78
+ poolInfo.underlyingMint.address,
79
+ poolInfo.underlyingMint.decimals,
80
+ program.methods,
81
+ publicKey,
82
+ wallet,
83
+ ])
84
+
85
+ return (
86
+ <SolanaTxSendModal
87
+ tx={transaction}
88
+ chainId={poolInfo.chainId}
89
+ handleSuccess={handleSuccess}
90
+ />
91
+ )
92
+ }
@@ -0,0 +1,59 @@
1
+ import { formatNumber, SolanaPoolInfo } from '@huma-finance/shared'
2
+ import React, { useEffect, useMemo, useState } from 'react'
3
+
4
+ import { useConnection } from '@solana/wallet-adapter-react'
5
+ import { useAppSelector } from '../../../hooks/useRedux'
6
+ import { selectWidgetState } from '../../../store/widgets.selectors'
7
+ import { SolanaTxDoneModal } from '../../SolanaTxDoneModal'
8
+
9
+ type Props = {
10
+ poolInfo: SolanaPoolInfo
11
+ handleAction: () => void
12
+ }
13
+
14
+ export function Done({ poolInfo, handleAction }: Props): React.ReactElement {
15
+ const { solanaSignature } = useAppSelector(selectWidgetState)
16
+ const { symbol } = poolInfo.underlyingMint
17
+ const { connection } = useConnection()
18
+ const [tokensPaid, setTokensPaid] = useState<number | null>(null)
19
+
20
+ useEffect(() => {
21
+ const fetchTokensPaid = async () => {
22
+ if (!solanaSignature) {
23
+ return
24
+ }
25
+
26
+ const txData = await connection.getTransaction(solanaSignature, {
27
+ maxSupportedTransactionVersion: 2,
28
+ })
29
+
30
+ const preTokenBalance =
31
+ txData?.meta?.preTokenBalances?.[1]?.uiTokenAmount?.uiAmount
32
+ const postTokenBalance =
33
+ txData?.meta?.postTokenBalances?.[1]?.uiTokenAmount?.uiAmount
34
+ if (preTokenBalance && postTokenBalance) {
35
+ setTokensPaid(preTokenBalance - postTokenBalance)
36
+ }
37
+ }
38
+
39
+ fetchTokensPaid()
40
+ }, [connection, solanaSignature])
41
+
42
+ const content = useMemo(() => {
43
+ if (tokensPaid !== null) {
44
+ return [`You successfully paid ${formatNumber(tokensPaid)} ${symbol}.`]
45
+ }
46
+
47
+ return ['Your payment to the pool was successful']
48
+ }, [tokensPaid, symbol])
49
+
50
+ return (
51
+ <SolanaTxDoneModal
52
+ handleAction={handleAction}
53
+ content={content}
54
+ chainId={poolInfo.chainId}
55
+ solanaSignature={solanaSignature}
56
+ buttonText='DONE'
57
+ />
58
+ )
59
+ }