1
- import React , { useMemo , useState } from 'react' ;
2
- import Button from '@popup/popupX/shared/Button' ;
3
- import { Navigate , useLocation , useNavigate , useParams } from 'react-router-dom' ;
4
- import { displayNameAndSplitAddress , displaySplitAddress , useCredential } from '@popup/shared/utils/account-helpers' ;
1
+ import React , { useState } from 'react' ;
2
+ import { Navigate , useLocation , useParams } from 'react-router-dom' ;
5
3
import { useTranslation } from 'react-i18next' ;
6
- import Page from '@popup/popupX/shared/Page' ;
7
- import Text from '@popup/popupX/shared/Text' ;
8
- import TokenAmount , { AmountReceiveForm } from '@popup/popupX/shared/Form/TokenAmount' ;
9
- import Form , { useForm } from '@popup/popupX/shared/Form' ;
10
4
import {
11
5
AccountAddress ,
12
6
AccountTransactionType ,
13
7
CIS2 ,
14
8
CIS2Contract ,
15
9
CcdAmount ,
16
- ContractAddress ,
10
+ Energy ,
17
11
SimpleTransferPayload ,
18
- TransactionHash ,
19
12
} from '@concordium/web-sdk' ;
13
+ import { useAsyncMemo } from 'wallet-common-helpers' ;
14
+ import { useAtomValue } from 'jotai' ;
15
+
16
+ import Button from '@popup/popupX/shared/Button' ;
17
+ import { displayNameAndSplitAddress , useCredential } from '@popup/shared/utils/account-helpers' ;
18
+ import Page from '@popup/popupX/shared/Page' ;
19
+ import Text from '@popup/popupX/shared/Text' ;
20
+ import TokenAmount , { AmountReceiveForm } from '@popup/popupX/shared/Form/TokenAmount' ;
21
+ import Form , { useForm } from '@popup/popupX/shared/Form' ;
20
22
import { useAccountInfo } from '@popup/shared/AccountInfoListenerContext' ;
21
23
import { useGetTransactionFee } from '@popup/shared/utils/transaction-helpers' ;
22
- import FullscreenNotice from '@popup/popupX/shared/FullscreenNotice' ;
23
- import Arrow from '@assets/svgX/arrow-right.svg' ;
24
- import { submittedTransactionRoute } from '@popup/popupX/constants/routes' ;
25
24
import { TokenPickerVariant } from '@popup/popupX/shared/Form/TokenAmount/View' ;
26
25
import { parseTokenAmount } from '@popup/popupX/shared/utils/helpers' ;
27
- import { noOp , useAsyncMemo } from 'wallet-common-helpers' ;
28
- import { useAtomValue } from 'jotai' ;
29
26
import { grpcClientAtom } from '@popup/store/settings' ;
30
27
import { logError } from '@shared/utils/log-helpers' ;
31
- import { useTokenInfo } from '@popup/popupX/shared/Form/TokenAmount/util ' ;
32
- import { CCD_METADATA } from '@shared/constants/token-metadata ' ;
33
- import Card from '@popup/popupX/shared/Card ' ;
28
+ import FullscreenNotice from '@popup/popupX/shared/FullscreenNotice ' ;
29
+ import SendFundsConfirm from './Confirm ' ;
30
+ import { CIS2_TRANSFER_NRG_OFFSET , useTokenMetadata } from './util ' ;
34
31
35
32
type SendFundsProps = { address : AccountAddress . Type } ;
36
33
export type SendFundsLocationState = TokenPickerVariant ;
37
34
38
35
function SendFunds ( { address } : SendFundsProps ) {
39
36
const { t } = useTranslation ( 'x' , { keyPrefix : 'sendFunds' } ) ;
40
37
const { state } = useLocation ( ) as { state : SendFundsLocationState | null } ;
41
- const nav = useNavigate ( ) ;
42
38
const credential = useCredential ( address . address ) ;
43
39
const grpcClient = useAtomValue ( grpcClientAtom ) ;
44
40
const form = useForm < AmountReceiveForm > ( {
45
41
mode : 'onTouched' ,
46
42
defaultValues : {
43
+ token : state ?? { tokenType : 'ccd' } ,
47
44
amount : '0.00' ,
48
45
} ,
49
46
} ) ;
@@ -56,46 +53,37 @@ function SendFunds({ address }: SendFundsProps) {
56
53
}
57
54
return CIS2Contract . create ( grpcClient , token . tokenAddress . contract ) ;
58
55
} ,
59
- noOp ,
56
+ logError ,
60
57
[ token , grpcClient ]
61
58
) ;
62
- const tokens = useTokenInfo ( address ) ;
63
- const tokenName = useMemo ( ( ) => {
64
- if ( tokens . loading ) return undefined ;
65
- if ( token ?. tokenType === undefined ) return undefined ;
66
-
67
- if ( token . tokenType === 'ccd' ) {
68
- return CCD_METADATA . symbol ;
69
- }
70
-
71
- const { metadata } =
72
- tokens . value . find (
73
- ( tk ) =>
74
- tk . id === token . tokenAddress . id && ContractAddress . equals ( tk . contract , token . tokenAddress . contract )
75
- ) ?? { } ;
76
- if ( metadata === undefined ) return undefined ;
77
-
78
- const safeName =
79
- metadata . symbol ?? metadata . name ?? `${ token . tokenAddress . id } @${ token . tokenAddress . contract . toString ( ) } ` ;
80
- return safeName ;
81
- } , [ tokens , token ] ) ;
82
59
83
60
const getFee = useGetTransactionFee ( ) ;
84
- const cost = useAsyncMemo (
61
+ const metadata = useTokenMetadata ( token , address ) ;
62
+ const fee = useAsyncMemo (
85
63
async ( ) => {
86
64
if ( token ?. tokenType === 'cis2' ) {
87
- if ( contractClient === undefined ) {
65
+ if ( contractClient === undefined || metadata === undefined ) {
66
+ return undefined ;
67
+ }
68
+
69
+ let tokenAmount : bigint ;
70
+ try {
71
+ tokenAmount = parseTokenAmount ( amount , metadata . decimals ) ;
72
+ } catch {
88
73
return undefined ;
89
74
}
90
75
91
76
const transfer : CIS2 . Transfer = {
92
77
from : address ,
93
78
to : address ,
94
79
tokenId : token . tokenAddress . id ,
95
- tokenAmount : parseTokenAmount ( amount ) ,
80
+ tokenAmount,
96
81
} ;
97
82
const result = await contractClient . dryRun . transfer ( address , transfer ) ;
98
- const { payload } = contractClient . createTransfer ( { energy : result . usedEnergy } , transfer ) ;
83
+ const { payload } = contractClient . createTransfer (
84
+ { energy : Energy . create ( result . usedEnergy . value + CIS2_TRANSFER_NRG_OFFSET ) } ,
85
+ transfer
86
+ ) ;
99
87
return getFee ( AccountTransactionType . Update , payload ) ;
100
88
}
101
89
if ( token ?. tokenType === 'ccd' ) {
@@ -115,19 +103,15 @@ function SendFunds({ address }: SendFundsProps) {
115
103
const [ showConfirmationPage , setShowConfirmationPage ] = useState ( false ) ;
116
104
const onSubmit = ( ) => setShowConfirmationPage ( true ) ;
117
105
118
- // TODO:
119
- // 1. Submit transaction (see `Delegator/TransactionFlow`)
120
- // 2. Pass the transaction hash to the route function below
121
- const navToSubmitted = ( ) => nav ( submittedTransactionRoute ( TransactionHash . fromHexString ( '..' ) ) ) ;
122
-
123
- const receiver : string | undefined = form . watch ( 'receiver' ) ;
124
-
125
106
if ( accountInfo === undefined ) {
126
107
return null ;
127
108
}
128
109
129
110
return (
130
111
< >
112
+ < FullscreenNotice open = { showConfirmationPage } onClose = { ( ) => setShowConfirmationPage ( false ) } >
113
+ { fee && < SendFundsConfirm sender = { address } values = { form . getValues ( ) } fee = { fee } /> }
114
+ </ FullscreenNotice >
131
115
< Page className = "send-funds-container" >
132
116
< Page . Top heading = { t ( 'sendFunds' ) } >
133
117
< Text . Capture className = "m-l-5 m-t-neg-5" >
@@ -139,47 +123,23 @@ function SendFunds({ address }: SendFundsProps) {
139
123
< TokenAmount
140
124
buttonMaxLabel = { t ( 'sendMax' ) }
141
125
receiver
142
- fee = { cost ?? CcdAmount . zero ( ) }
126
+ fee = { fee ?? CcdAmount . zero ( ) }
143
127
form = { form }
144
128
accountInfo = { accountInfo }
145
129
{ ...state }
146
130
/>
147
131
) }
148
132
</ Form >
149
133
{ /*
150
- <div className="send-funds__memo">
151
- <Plus />
152
- <span className="label__main">Add memo</span>
153
- </div>
154
- */ }
134
+ <div className="send-funds__memo">
135
+ <Plus />
136
+ <span className="label__main">Add memo</span>
137
+ </div>
138
+ */ }
155
139
< Page . Footer >
156
140
< Button . Main className = "button-main" onClick = { form . handleSubmit ( onSubmit ) } label = "Continue" />
157
141
</ Page . Footer >
158
142
</ Page >
159
- { /* Confirmation page modal */ }
160
- < FullscreenNotice open = { showConfirmationPage } onClose = { ( ) => setShowConfirmationPage ( false ) } >
161
- < Page className = "send-funds-container" >
162
- < Page . Top heading = { t ( 'confirmation.title' ) } />
163
-
164
- < Card className = "send-funds-confirm__card" type = "transparent" >
165
- < div className = "send-funds-confirm__card_destination" >
166
- < Text . MainMedium > { displayNameAndSplitAddress ( credential ) } </ Text . MainMedium >
167
- < Arrow />
168
- < Text . MainMedium > { receiver && displaySplitAddress ( receiver ) } </ Text . MainMedium >
169
- </ div >
170
- < Text . Capture >
171
- { t ( 'amount' ) } ({ tokenName }
172
- ):
173
- </ Text . Capture >
174
- < Text . HeadingLarge > { form . watch ( 'amount' ) } </ Text . HeadingLarge >
175
- < Text . Capture > { t ( 'estimatedFee' , { fee : cost } ) } </ Text . Capture >
176
- </ Card >
177
-
178
- < Page . Footer >
179
- < Button . Main className = "button-main" onClick = { navToSubmitted } label = { t ( 'sendFunds' ) } />
180
- </ Page . Footer >
181
- </ Page >
182
- </ FullscreenNotice >
183
143
</ >
184
144
) ;
185
145
}
0 commit comments