Skip to content

Commit 5948b77

Browse files
authored
better flow for EOA accounts + multiple TXs in Checkout flow (#544)
* modified sendTransactions function * integrate tx counter * added multiple transaction tracking for price section * clean up * closure fix * added error messages
1 parent 0daf6c5 commit 5948b77

File tree

7 files changed

+289
-89
lines changed

7 files changed

+289
-89
lines changed

packages/checkout/src/hooks/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ export * from './useCheckoutOptionsSalesContract.js'
1010
export * from './useERC1155SaleContractCheckout.js'
1111
export * from './useSkipOnCloseCallback.js'
1212
export * from './useFortePaymentIntent.js'
13+
export * from './useAddFundsModal.js'
14+
export * from './useTransactionCounter.js'

packages/checkout/src/hooks/useCheckoutUI/useCryptoPayment.tsx

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,8 @@ export const useCryptoPayment = ({
238238
}
239239
]
240240

241-
const txHash = await sendTransactions({
241+
let txHash: string | undefined
242+
const txs = await sendTransactions({
242243
chainId,
243244
senderAddress: userAddress,
244245
publicClient,
@@ -250,7 +251,25 @@ export const useCryptoPayment = ({
250251
waitConfirmationForLastTransaction: false
251252
})
252253

253-
onSuccess?.(txHash)
254+
if (txs.length === 0) {
255+
throw new Error('No transactions to send')
256+
}
257+
258+
for (const [index, tx] of txs.entries()) {
259+
const currentTxHash = await tx()
260+
261+
const isLastTransaction = index === txs.length - 1
262+
263+
if (isLastTransaction) {
264+
onSuccess?.(currentTxHash)
265+
txHash = currentTxHash
266+
}
267+
}
268+
269+
if (!txHash) {
270+
throw new Error('Transaction hash is not available')
271+
}
272+
254273
return txHash
255274
} else {
256275
const swapOption = swapRoutes
@@ -322,7 +341,8 @@ export const useCryptoPayment = ({
322341
}
323342
]
324343

325-
const txHash = await sendTransactions({
344+
let txHash: string | undefined
345+
const txs = await sendTransactions({
326346
chainId,
327347
senderAddress: userAddress,
328348
publicClient,
@@ -334,7 +354,25 @@ export const useCryptoPayment = ({
334354
waitConfirmationForLastTransaction: false
335355
})
336356

337-
onSuccess?.(txHash)
357+
if (txs.length === 0) {
358+
throw new Error('No transactions to send')
359+
}
360+
361+
for (const [index, tx] of txs.entries()) {
362+
const currentTxHash = await tx()
363+
364+
const isLastTransaction = index === txs.length - 1
365+
366+
if (isLastTransaction) {
367+
onSuccess?.(currentTxHash)
368+
txHash = currentTxHash
369+
}
370+
}
371+
372+
if (!txHash) {
373+
throw new Error('Transaction hash is not available')
374+
}
375+
338376
return txHash
339377
}
340378
} catch (error) {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useState } from 'react'
2+
3+
export const useTransactionCounter = () => {
4+
const [currentTransactionNumber, setCurrentTransactionNumber] = useState(1)
5+
const [maxTransactions, setMaxTransactions] = useState(0)
6+
7+
const initializeTransactionCounter = (maxTransactions: number) => {
8+
setCurrentTransactionNumber(1)
9+
setMaxTransactions(maxTransactions)
10+
}
11+
12+
const resetTransactionCounter = () => {
13+
setCurrentTransactionNumber(1)
14+
setMaxTransactions(0)
15+
}
16+
17+
const incrementTransactionCount = () => {
18+
setCurrentTransactionNumber(prev => prev + 1)
19+
}
20+
21+
const isTransactionCounterInitialized = maxTransactions > 0
22+
23+
return {
24+
currentTransactionNumber,
25+
maxTransactions,
26+
incrementTransactionCount,
27+
initializeTransactionCounter,
28+
resetTransactionCounter,
29+
isTransactionCounterInitialized
30+
}
31+
}

packages/checkout/src/views/Checkout/PaymentMethodSelect/PayWithCrypto/index.tsx

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { ERC_20_CONTRACT_ABI } from '../../../../constants/abi.js'
2626
import { EVENT_SOURCE } from '../../../../constants/index.js'
2727
import { type PaymentMethodSelectionParams } from '../../../../contexts/NavigationCheckout.js'
2828
import type { SelectPaymentSettings } from '../../../../contexts/SelectPaymentModal.js'
29-
import { useAddFundsModal } from '../../../../hooks/index.js'
29+
import { useAddFundsModal, useTransactionCounter } from '../../../../hooks/index.js'
3030
import { useSelectPaymentModal, useTransactionStatusModal } from '../../../../hooks/index.js'
3131
import { useNavigationCheckout } from '../../../../hooks/useNavigationCheckout.js'
3232

@@ -48,6 +48,14 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P
4848
const { analytics } = useAnalyticsContext()
4949
const [isError, setIsError] = useState<boolean>(false)
5050
const { navigation, setNavigation } = useNavigationCheckout()
51+
const {
52+
initializeTransactionCounter,
53+
incrementTransactionCount,
54+
currentTransactionNumber,
55+
maxTransactions,
56+
isTransactionCounterInitialized,
57+
resetTransactionCounter
58+
} = useTransactionCounter()
5159

5260
const {
5361
chain,
@@ -275,7 +283,7 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P
275283
}
276284
]
277285

278-
const txHash = await sendTransactions({
286+
const txs = await sendTransactions({
279287
chainId,
280288
senderAddress: userAddress,
281289
publicClient,
@@ -287,6 +295,29 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P
287295
waitConfirmationForLastTransaction: false
288296
})
289297

298+
if (txs.length === 0) {
299+
throw new Error('No transactions to send')
300+
}
301+
302+
initializeTransactionCounter(txs.length)
303+
304+
let txHash: string | undefined
305+
for (const [index, tx] of txs.entries()) {
306+
const currentTxHash = await tx()
307+
incrementTransactionCount()
308+
309+
const isLastTransaction = index === txs.length - 1
310+
311+
if (isLastTransaction) {
312+
onSuccess?.(currentTxHash)
313+
txHash = currentTxHash
314+
}
315+
}
316+
317+
if (!txHash) {
318+
throw new Error('Transaction hash is not available')
319+
}
320+
290321
analytics?.track({
291322
event: 'SEND_TRANSACTION_REQUEST',
292323
props: {
@@ -340,6 +371,7 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P
340371
setIsError(true)
341372
}
342373

374+
resetTransactionCounter()
343375
setIsPurchasing(false)
344376
}
345377

@@ -423,7 +455,7 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P
423455
}
424456
]
425457

426-
const txHash = await sendTransactions({
458+
const txs = await sendTransactions({
427459
chainId,
428460
senderAddress: userAddress,
429461
publicClient,
@@ -435,6 +467,29 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P
435467
waitConfirmationForLastTransaction: false
436468
})
437469

470+
if (txs.length === 0) {
471+
throw new Error('No transactions to send')
472+
}
473+
474+
initializeTransactionCounter(txs.length)
475+
476+
let txHash: string | undefined
477+
for (const [index, tx] of txs.entries()) {
478+
const currentTxHash = await tx()
479+
incrementTransactionCount()
480+
481+
const isLastTransaction = index === txs.length - 1
482+
483+
if (isLastTransaction) {
484+
onSuccess?.(currentTxHash)
485+
txHash = currentTxHash
486+
}
487+
}
488+
489+
if (!txHash) {
490+
throw new Error('Transaction hash is not available')
491+
}
492+
438493
analytics?.track({
439494
event: 'SEND_TRANSACTION_REQUEST',
440495
props: {
@@ -489,6 +544,7 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P
489544
}
490545

491546
setIsPurchasing(false)
547+
resetTransactionCounter()
492548
}
493549

494550
const onClickPurchase = () => {
@@ -612,6 +668,23 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P
612668
}
613669

614670
const PriceSection = () => {
671+
if (isTransactionCounterInitialized) {
672+
const descriptionText =
673+
maxTransactions > 1
674+
? `Confirming transaction ${currentTransactionNumber} of ${maxTransactions}`
675+
: `Confirming transaction`
676+
return (
677+
<div className="flex flex-col flex-wrap justify-between items-center w-full gap-2">
678+
<div className="flex flex-col gap-0.5">
679+
<Text variant="xsmall" color="text50">
680+
{descriptionText}
681+
</Text>
682+
</div>
683+
<Spinner />
684+
</div>
685+
)
686+
}
687+
615688
if (isFree) {
616689
return (
617690
<div className="flex flex-col mt-2 mb-1 w-full">

packages/checkout/src/views/Swap/index.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ export const Swap = () => {
237237
await walletClient.switchChain({ id: chainId })
238238
}
239239

240-
const txHash = await sendTransactions({
240+
const txs = await sendTransactions({
241241
connector,
242242
walletClient,
243243
publicClient,
@@ -248,6 +248,26 @@ export const Swap = () => {
248248
transactions: [...getSwapTransactions(), ...(postSwapTransactions ?? [])]
249249
})
250250

251+
if (txs.length === 0) {
252+
throw new Error('No transactions to send')
253+
}
254+
255+
let txHash: string | undefined
256+
257+
for (const [index, tx] of txs.entries()) {
258+
const currentTxHash = await tx()
259+
260+
const isLastTransaction = index === txs.length - 1
261+
if (isLastTransaction) {
262+
onSuccess?.(currentTxHash)
263+
txHash = currentTxHash
264+
}
265+
}
266+
267+
if (!txHash) {
268+
throw new Error('Transaction hash is not available')
269+
}
270+
251271
closeSwapModal()
252272
openTransactionStatusModal({
253273
chainId,

0 commit comments

Comments
 (0)