thirdweb 5.87.4 → 5.88.0

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.
Files changed (149) hide show
  1. package/dist/cjs/client/client.js +2 -1
  2. package/dist/cjs/client/client.js.map +1 -1
  3. package/dist/cjs/contract/deployment/zksync/zkDeployContract.js +4 -2
  4. package/dist/cjs/contract/deployment/zksync/zkDeployContract.js.map +1 -1
  5. package/dist/cjs/pay/buyWithCrypto/getQuote.js +1 -24
  6. package/dist/cjs/pay/buyWithCrypto/getQuote.js.map +1 -1
  7. package/dist/cjs/pay/buyWithCrypto/getTransfer.js +1 -13
  8. package/dist/cjs/pay/buyWithCrypto/getTransfer.js.map +1 -1
  9. package/dist/cjs/pay/buyWithFiat/getQuote.js.map +1 -1
  10. package/dist/cjs/pay/utils/commonTypes.js +2 -0
  11. package/dist/cjs/pay/utils/commonTypes.js.map +1 -1
  12. package/dist/cjs/react/core/utils/storage.js +2 -1
  13. package/dist/cjs/react/core/utils/storage.js.map +1 -1
  14. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +50 -200
  15. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  16. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.js +111 -0
  17. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.js.map +1 -0
  18. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.js +30 -2
  19. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.js.map +1 -1
  20. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.js +24 -0
  21. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.js.map +1 -0
  22. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js +2 -1
  23. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js.map +1 -1
  24. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js +18 -6
  25. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js.map +1 -1
  26. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js +37 -0
  27. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js.map +1 -0
  28. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.js +1 -1
  29. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.js.map +1 -1
  30. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.js +165 -0
  31. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.js.map +1 -0
  32. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.js +33 -6
  33. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.js.map +1 -1
  34. package/dist/cjs/react/web/ui/ConnectWallet/screens/nativeToken.js +8 -0
  35. package/dist/cjs/react/web/ui/ConnectWallet/screens/nativeToken.js.map +1 -1
  36. package/dist/cjs/react/web/utils/errors.js +16 -0
  37. package/dist/cjs/react/web/utils/errors.js.map +1 -0
  38. package/dist/cjs/version.js +1 -1
  39. package/dist/cjs/wallets/smart/index.js +27 -0
  40. package/dist/cjs/wallets/smart/index.js.map +1 -1
  41. package/dist/cjs/wallets/smart/types.js.map +1 -1
  42. package/dist/esm/client/client.js +2 -1
  43. package/dist/esm/client/client.js.map +1 -1
  44. package/dist/esm/contract/deployment/zksync/zkDeployContract.js +4 -2
  45. package/dist/esm/contract/deployment/zksync/zkDeployContract.js.map +1 -1
  46. package/dist/esm/pay/buyWithCrypto/getQuote.js +1 -24
  47. package/dist/esm/pay/buyWithCrypto/getQuote.js.map +1 -1
  48. package/dist/esm/pay/buyWithCrypto/getTransfer.js +1 -13
  49. package/dist/esm/pay/buyWithCrypto/getTransfer.js.map +1 -1
  50. package/dist/esm/pay/buyWithFiat/getQuote.js.map +1 -1
  51. package/dist/esm/pay/utils/commonTypes.js +1 -1
  52. package/dist/esm/pay/utils/commonTypes.js.map +1 -1
  53. package/dist/esm/react/core/utils/storage.js +1 -0
  54. package/dist/esm/react/core/utils/storage.js.map +1 -1
  55. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +50 -200
  56. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  57. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.js +108 -0
  58. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.js.map +1 -0
  59. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.js +30 -2
  60. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.js.map +1 -1
  61. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.js +21 -0
  62. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.js.map +1 -0
  63. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js +2 -1
  64. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js.map +1 -1
  65. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js +18 -6
  66. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js.map +1 -1
  67. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js +34 -0
  68. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js.map +1 -0
  69. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.js +1 -1
  70. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.js.map +1 -1
  71. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.js +162 -0
  72. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.js.map +1 -0
  73. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.js +33 -6
  74. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.js.map +1 -1
  75. package/dist/esm/react/web/ui/ConnectWallet/screens/nativeToken.js +7 -0
  76. package/dist/esm/react/web/ui/ConnectWallet/screens/nativeToken.js.map +1 -1
  77. package/dist/esm/react/web/utils/errors.js +12 -0
  78. package/dist/esm/react/web/utils/errors.js.map +1 -0
  79. package/dist/esm/version.js +1 -1
  80. package/dist/esm/wallets/smart/index.js +27 -0
  81. package/dist/esm/wallets/smart/index.js.map +1 -1
  82. package/dist/esm/wallets/smart/types.js.map +1 -1
  83. package/dist/types/client/client.d.ts.map +1 -1
  84. package/dist/types/contract/deployment/zksync/zkDeployContract.d.ts.map +1 -1
  85. package/dist/types/pay/buyWithCrypto/getQuote.d.ts +2 -2
  86. package/dist/types/pay/buyWithCrypto/getQuote.d.ts.map +1 -1
  87. package/dist/types/pay/buyWithCrypto/getTransfer.d.ts +2 -2
  88. package/dist/types/pay/buyWithCrypto/getTransfer.d.ts.map +1 -1
  89. package/dist/types/pay/buyWithFiat/getQuote.d.ts +4 -0
  90. package/dist/types/pay/buyWithFiat/getQuote.d.ts.map +1 -1
  91. package/dist/types/pay/utils/commonTypes.d.ts +2 -1
  92. package/dist/types/pay/utils/commonTypes.d.ts.map +1 -1
  93. package/dist/types/react/core/utils/storage.d.ts +1 -0
  94. package/dist/types/react/core/utils/storage.d.ts.map +1 -1
  95. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.d.ts.map +1 -1
  96. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.d.ts +25 -0
  97. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.d.ts.map +1 -0
  98. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.d.ts.map +1 -1
  99. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.d.ts +9 -0
  100. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.d.ts.map +1 -0
  101. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/types.d.ts +1 -0
  102. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/types.d.ts.map +1 -1
  103. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.d.ts.map +1 -1
  104. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.d.ts +1 -0
  105. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.d.ts.map +1 -1
  106. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.d.ts +11 -0
  107. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.d.ts.map +1 -0
  108. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.d.ts +1 -0
  109. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.d.ts.map +1 -1
  110. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.d.ts +31 -0
  111. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.d.ts.map +1 -0
  112. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.d.ts.map +1 -1
  113. package/dist/types/react/web/ui/ConnectWallet/screens/nativeToken.d.ts +2 -0
  114. package/dist/types/react/web/ui/ConnectWallet/screens/nativeToken.d.ts.map +1 -1
  115. package/dist/types/react/web/ui/components/text.d.ts +1 -1
  116. package/dist/types/react/web/ui/components/text.d.ts.map +1 -1
  117. package/dist/types/react/web/utils/errors.d.ts +14 -0
  118. package/dist/types/react/web/utils/errors.d.ts.map +1 -0
  119. package/dist/types/version.d.ts +1 -1
  120. package/dist/types/wallets/smart/index.d.ts.map +1 -1
  121. package/dist/types/wallets/smart/types.d.ts +5 -0
  122. package/dist/types/wallets/smart/types.d.ts.map +1 -1
  123. package/package.json +1 -1
  124. package/src/client/client.test.ts +2 -2
  125. package/src/client/client.ts +2 -1
  126. package/src/contract/deployment/zksync/zkDeployContract.ts +5 -2
  127. package/src/pay/buyWithCrypto/getQuote.ts +2 -27
  128. package/src/pay/buyWithCrypto/getTransfer.ts +2 -14
  129. package/src/pay/buyWithFiat/getQuote.ts +5 -0
  130. package/src/pay/utils/commonTypes.ts +3 -1
  131. package/src/react/core/utils/storage.ts +1 -0
  132. package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +70 -531
  133. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.tsx +307 -0
  134. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.tsx +33 -1
  135. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.tsx +57 -0
  136. package/src/react/web/ui/ConnectWallet/screens/Buy/main/types.ts +1 -0
  137. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.tsx +12 -2
  138. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.tsx +21 -6
  139. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx +51 -0
  140. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.tsx +2 -0
  141. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.tsx +353 -0
  142. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.tsx +43 -6
  143. package/src/react/web/ui/ConnectWallet/screens/nativeToken.ts +8 -0
  144. package/src/react/web/ui/components/text.tsx +1 -1
  145. package/src/react/web/utils/errors.ts +22 -0
  146. package/src/version.ts +1 -1
  147. package/src/wallets/smart/index.ts +28 -0
  148. package/src/wallets/smart/smart-wallet-integration.test.ts +25 -0
  149. package/src/wallets/smart/types.ts +5 -0
@@ -3,24 +3,19 @@ import { useCallback, useMemo, useState } from "react";
3
3
  import type { Chain } from "../../../../../../chains/types.js";
4
4
  import type { ThirdwebClient } from "../../../../../../client/client.js";
5
5
  import { NATIVE_TOKEN_ADDRESS } from "../../../../../../constants/addresses.js";
6
- import type { GetBuyWithCryptoQuoteParams } from "../../../../../../pay/buyWithCrypto/getQuote.js";
7
6
  import type { BuyWithCryptoStatus } from "../../../../../../pay/buyWithCrypto/getStatus.js";
8
7
  import type { BuyWithFiatStatus } from "../../../../../../pay/buyWithFiat/getStatus.js";
9
- import { isSwapRequiredPostOnramp } from "../../../../../../pay/buyWithFiat/isSwapRequiredPostOnramp.js";
10
- import { formatNumber } from "../../../../../../utils/formatNumber.js";
11
8
  import type { Account } from "../../../../../../wallets/interfaces/wallet.js";
12
9
  import type { WalletId } from "../../../../../../wallets/wallet-types.js";
13
10
  import {
14
11
  type Theme,
12
+ fontSize,
15
13
  spacing,
16
14
  } from "../../../../../core/design-system/index.js";
17
15
  import type {
18
16
  FundWalletOptions,
19
17
  PayUIOptions,
20
18
  } from "../../../../../core/hooks/connection/ConnectButtonProps.js";
21
- import { useWalletBalance } from "../../../../../core/hooks/others/useWalletBalance.js";
22
- import { useBuyWithCryptoQuote } from "../../../../../core/hooks/pay/useBuyWithCryptoQuote.js";
23
- import { useBuyWithFiatQuote } from "../../../../../core/hooks/pay/useBuyWithFiatQuote.js";
24
19
  import { useActiveAccount } from "../../../../../core/hooks/wallets/useActiveAccount.js";
25
20
  import { invalidateWalletBalance } from "../../../../../core/providers/invalidateWalletBalance.js";
26
21
  import type { SupportedTokens } from "../../../../../core/utils/defaultTokens.js";
@@ -28,16 +23,10 @@ import { ErrorState } from "../../../../wallets/shared/ErrorState.js";
28
23
  import { LoadingScreen } from "../../../../wallets/shared/LoadingScreen.js";
29
24
  import type { PayEmbedConnectOptions } from "../../../PayEmbed.js";
30
25
  import { ChainName } from "../../../components/ChainName.js";
31
- import {
32
- Drawer,
33
- DrawerOverlay,
34
- useDrawer,
35
- } from "../../../components/Drawer.js";
36
26
  import { Spacer } from "../../../components/Spacer.js";
37
- import { Spinner } from "../../../components/Spinner.js";
38
- import { SwitchNetworkButton } from "../../../components/SwitchNetwork.js";
39
27
  import { Container, Line, ModalHeader } from "../../../components/basic.js";
40
28
  import { Button } from "../../../components/buttons.js";
29
+ import { Input } from "../../../components/formElements.js";
41
30
  import { Text } from "../../../components/text.js";
42
31
  import { TokenSymbol } from "../../../components/token/TokenSymbol.js";
43
32
  import { ConnectButton } from "../../ConnectButton.js";
@@ -47,13 +36,11 @@ import { TokenSelector } from "../TokenSelector.js";
47
36
  import { WalletSwitcherConnectionScreen } from "../WalletSwitcherConnectionScreen.js";
48
37
  import { type ERC20OrNativeToken, isNativeToken } from "../nativeToken.js";
49
38
  import { DirectPaymentModeScreen } from "./DirectPaymentModeScreen.js";
50
- import { EstimatedTimeAndFees } from "./EstimatedTimeAndFees.js";
51
39
  import { PayTokenIcon } from "./PayTokenIcon.js";
52
- import { PayWithCreditCard } from "./PayWIthCreditCard.js";
53
40
  import { TransactionModeScreen } from "./TransactionModeScreen.js";
54
41
  import { CurrencySelection } from "./fiat/CurrencySelection.js";
55
42
  import { FiatFlow } from "./fiat/FiatFlow.js";
56
- import type { CurrencyMeta } from "./fiat/currencies.js";
43
+ import { FiatScreenContent } from "./fiat/FiatScreenContent.js";
57
44
  import type { SelectedScreen } from "./main/types.js";
58
45
  import {
59
46
  type PaymentMethods,
@@ -64,20 +51,16 @@ import {
64
51
  useFromTokenSelectionStates,
65
52
  useToTokenSelectionStates,
66
53
  } from "./main/useUISelectionStates.js";
67
- import { openOnrampPopup } from "./openOnRamppopup.js";
68
54
  import { BuyTokenInput } from "./swap/BuyTokenInput.js";
69
- import { FiatFees, SwapFees } from "./swap/Fees.js";
70
- import { PayWithCryptoQuoteInfo } from "./swap/PayWithCrypto.js";
71
55
  import { PaymentSelectionScreen } from "./swap/PaymentSelectionScreen.js";
72
56
  import { SwapFlow } from "./swap/SwapFlow.js";
57
+ import { SwapScreenContent } from "./swap/SwapScreenContent.js";
73
58
  import { TransferFlow } from "./swap/TransferFlow.js";
74
- import { addPendingTx } from "./swap/pendingSwapTx.js";
75
59
  import {
76
60
  type SupportedChainAndTokens,
77
61
  useBuySupportedDestinations,
78
62
  useBuySupportedSources,
79
63
  } from "./swap/useSwapSupportedChains.js";
80
- import type { PayerInfo } from "./types.js";
81
64
  import { usePayerSetup } from "./usePayerSetup.js";
82
65
 
83
66
  export type BuyScreenProps = {
@@ -322,6 +305,7 @@ function BuyScreenContent(props: BuyScreenContentProps) {
322
305
  });
323
306
  }}
324
307
  onSuccess={onSwapSuccess}
308
+ approvalAmount={screen.approvalAmount}
325
309
  />
326
310
  );
327
311
  }
@@ -536,6 +520,7 @@ function BuyScreenContent(props: BuyScreenContentProps) {
536
520
  selectedChain={toChain}
537
521
  selectedToken={toToken}
538
522
  tokenAmount={tokenAmount}
523
+ setTokenAmount={setTokenAmount}
539
524
  client={client}
540
525
  onBack={() => {
541
526
  if (
@@ -663,8 +648,17 @@ function SelectedTokenInfo(props: {
663
648
  selectedToken: ERC20OrNativeToken;
664
649
  selectedChain: Chain;
665
650
  tokenAmount: string;
651
+ setTokenAmount: (amount: string) => void;
666
652
  client: ThirdwebClient;
667
653
  }) {
654
+ const getWidth = () => {
655
+ let chars = props.tokenAmount.replace(".", "").length;
656
+ const hasDot = props.tokenAmount.includes(".");
657
+ if (hasDot) {
658
+ chars += 0.3;
659
+ }
660
+ return `calc(${`${Math.max(1, chars)}ch + 2px`})`;
661
+ };
668
662
  return (
669
663
  <div>
670
664
  <Container
@@ -676,9 +670,59 @@ function SelectedTokenInfo(props: {
676
670
  }}
677
671
  >
678
672
  <Container flex="row" gap="xs" center="y">
679
- <Text color="primaryText" data-testid="tokenAmount" size="xl">
680
- {formatNumber(Number(props.tokenAmount), 6)}
681
- </Text>
673
+ <Input
674
+ variant="outline"
675
+ pattern="^[0-9]*[.,]?[0-9]*$"
676
+ inputMode="decimal"
677
+ tabIndex={-1}
678
+ placeholder="0"
679
+ type="text"
680
+ data-placeholder={props.tokenAmount === ""}
681
+ value={props.tokenAmount || "0"}
682
+ disabled={false} // TODO: add disabled freeze amount
683
+ onClick={(e) => {
684
+ // put cursor at the end of the input
685
+ if (props.tokenAmount === "") {
686
+ e.currentTarget.setSelectionRange(
687
+ e.currentTarget.value.length,
688
+ e.currentTarget.value.length,
689
+ );
690
+ }
691
+ }}
692
+ onChange={(e) => {
693
+ let value = e.target.value;
694
+
695
+ if (value.startsWith(".")) {
696
+ value = `0${value}`;
697
+ }
698
+
699
+ if (value.length > 10) {
700
+ return;
701
+ }
702
+
703
+ const numValue = Number(value);
704
+ if (Number.isNaN(numValue)) {
705
+ return;
706
+ }
707
+
708
+ if (value.startsWith("0") && !value.startsWith("0.")) {
709
+ props.setTokenAmount(value.slice(1));
710
+ } else {
711
+ props.setTokenAmount(value);
712
+ }
713
+ }}
714
+ style={{
715
+ border: "none",
716
+ fontSize: fontSize.lg,
717
+ boxShadow: "none",
718
+ borderRadius: "0",
719
+ padding: "0",
720
+ paddingBlock: "2px",
721
+ fontWeight: 600,
722
+ textAlign: "left",
723
+ width: getWidth(),
724
+ }}
725
+ />
682
726
 
683
727
  <Container flex="row" gap="xxs" center="y">
684
728
  <TokenSymbol
@@ -866,6 +910,7 @@ function TokenSelectedLayout(props: {
866
910
  title: string;
867
911
  children: React.ReactNode;
868
912
  tokenAmount: string;
913
+ setTokenAmount: (amount: string) => void;
869
914
  selectedToken: ERC20OrNativeToken;
870
915
  selectedChain: Chain;
871
916
  client: ThirdwebClient;
@@ -888,6 +933,7 @@ function TokenSelectedLayout(props: {
888
933
  selectedToken={props.selectedToken}
889
934
  selectedChain={props.selectedChain}
890
935
  tokenAmount={props.tokenAmount}
936
+ setTokenAmount={props.setTokenAmount}
891
937
  client={props.client}
892
938
  />
893
939
 
@@ -904,490 +950,6 @@ function TokenSelectedLayout(props: {
904
950
  );
905
951
  }
906
952
 
907
- function SwapScreenContent(props: {
908
- setScreen: (screen: SelectedScreen) => void;
909
- tokenAmount: string;
910
- toToken: ERC20OrNativeToken;
911
- toChain: Chain;
912
- fromChain: Chain;
913
- fromToken: ERC20OrNativeToken;
914
- showFromTokenSelector: () => void;
915
- payer: PayerInfo;
916
- client: ThirdwebClient;
917
- payOptions: PayUIOptions;
918
- isEmbed: boolean;
919
- onDone: () => void;
920
- connectOptions: PayEmbedConnectOptions | undefined;
921
- connectLocale: ConnectLocale;
922
- setPayer: (payer: PayerInfo) => void;
923
- activeAccount: Account;
924
- setTokenAmount: (amount: string) => void;
925
- setHasEditedAmount: (hasEdited: boolean) => void;
926
- disableTokenSelection: boolean;
927
- }) {
928
- const {
929
- setScreen,
930
- payer,
931
- client,
932
- toChain,
933
- tokenAmount,
934
- toToken,
935
- fromChain,
936
- fromToken,
937
- payOptions,
938
- disableTokenSelection,
939
- } = props;
940
-
941
- const defaultRecipientAddress = (
942
- props.payOptions as Extract<PayUIOptions, { mode: "direct_payment" }>
943
- )?.paymentInfo?.sellerAddress;
944
- const receiverAddress =
945
- defaultRecipientAddress || props.activeAccount.address;
946
- const { drawerRef, drawerOverlayRef, isOpen, setIsOpen } = useDrawer();
947
- const [drawerScreen, setDrawerScreen] = useState<
948
- "fees" | "receiver" | "payer"
949
- >("fees");
950
-
951
- const fromTokenBalanceQuery = useWalletBalance({
952
- address: payer.account.address,
953
- chain: fromChain,
954
- tokenAddress: isNativeToken(fromToken) ? undefined : fromToken.address,
955
- client,
956
- });
957
-
958
- const fromTokenId = isNativeToken(fromToken)
959
- ? NATIVE_TOKEN_ADDRESS
960
- : fromToken.address.toLowerCase();
961
- const toTokenId = isNativeToken(toToken)
962
- ? NATIVE_TOKEN_ADDRESS
963
- : toToken.address.toLowerCase();
964
- const swapRequired =
965
- !!tokenAmount &&
966
- !(fromChain.id === toChain.id && fromTokenId === toTokenId);
967
- const quoteParams: GetBuyWithCryptoQuoteParams | undefined = swapRequired
968
- ? {
969
- // wallets
970
- fromAddress: payer.account.address,
971
- toAddress: receiverAddress,
972
- // from
973
- fromChainId: fromChain.id,
974
- fromTokenAddress: isNativeToken(fromToken)
975
- ? NATIVE_TOKEN_ADDRESS
976
- : fromToken.address,
977
- // to
978
- toChainId: toChain.id,
979
- toTokenAddress: isNativeToken(toToken)
980
- ? NATIVE_TOKEN_ADDRESS
981
- : toToken.address,
982
- toAmount: tokenAmount,
983
- client,
984
- purchaseData: payOptions.purchaseData,
985
- }
986
- : undefined;
987
-
988
- const quoteQuery = useBuyWithCryptoQuote(quoteParams, {
989
- // refetch every 30 seconds
990
- staleTime: 30 * 1000,
991
- refetchInterval: 30 * 1000,
992
- gcTime: 30 * 1000,
993
- });
994
-
995
- const sourceTokenAmount = swapRequired
996
- ? quoteQuery.data?.swapDetails.fromAmount
997
- : tokenAmount;
998
-
999
- const isNotEnoughBalance =
1000
- !!sourceTokenAmount &&
1001
- !!fromTokenBalanceQuery.data &&
1002
- Number(fromTokenBalanceQuery.data.displayValue) < Number(sourceTokenAmount);
1003
-
1004
- const disableContinue =
1005
- (swapRequired && !quoteQuery.data) || isNotEnoughBalance;
1006
- const switchChainRequired =
1007
- props.payer.wallet.getChain()?.id !== fromChain.id;
1008
-
1009
- const errorMsg =
1010
- !quoteQuery.isLoading && quoteQuery.error
1011
- ? getErrorMessage(quoteQuery.error)
1012
- : undefined;
1013
-
1014
- function showSwapFlow() {
1015
- if (
1016
- (props.payOptions.mode === "direct_payment" ||
1017
- props.payOptions.mode === "fund_wallet") &&
1018
- !isNotEnoughBalance &&
1019
- !swapRequired
1020
- ) {
1021
- // same currency, just direct transfer
1022
- setScreen({
1023
- id: "transfer-flow",
1024
- });
1025
- } else if (
1026
- props.payOptions.mode === "transaction" &&
1027
- !isNotEnoughBalance &&
1028
- !swapRequired
1029
- ) {
1030
- if (payer.account.address !== receiverAddress) {
1031
- // needs transfer from another wallet before executing the transaction
1032
- setScreen({
1033
- id: "transfer-flow",
1034
- });
1035
- } else {
1036
- // has enough balance to just do the transaction directly
1037
- props.onDone();
1038
- }
1039
-
1040
- return;
1041
- }
1042
-
1043
- if (!quoteQuery.data) {
1044
- return;
1045
- }
1046
-
1047
- setScreen({
1048
- id: "swap-flow",
1049
- quote: quoteQuery.data,
1050
- });
1051
- }
1052
-
1053
- function showFees() {
1054
- if (!quoteQuery.data) {
1055
- return;
1056
- }
1057
-
1058
- setIsOpen(true);
1059
- setDrawerScreen("fees");
1060
- }
1061
-
1062
- return (
1063
- <Container flex="column" gap="md" animate="fadein">
1064
- {isOpen && (
1065
- <>
1066
- <DrawerOverlay ref={drawerOverlayRef} />
1067
- <Drawer ref={drawerRef} close={() => setIsOpen(false)}>
1068
- {drawerScreen === "fees" && quoteQuery.data && (
1069
- <div>
1070
- <Text size="lg" color="primaryText">
1071
- Fees
1072
- </Text>
1073
- <Spacer y="lg" />
1074
- <SwapFees quote={quoteQuery.data} />
1075
- </div>
1076
- )}
1077
- </Drawer>
1078
- </>
1079
- )}
1080
-
1081
- {/* Quote info */}
1082
- <div>
1083
- <PayWithCryptoQuoteInfo
1084
- value={sourceTokenAmount || ""}
1085
- chain={fromChain}
1086
- token={fromToken}
1087
- isLoading={quoteQuery.isLoading && !sourceTokenAmount}
1088
- client={client}
1089
- freezeChainAndTokenSelection={disableTokenSelection}
1090
- payerAccount={props.payer.account}
1091
- swapRequired={swapRequired}
1092
- />
1093
- {swapRequired && (
1094
- <EstimatedTimeAndFees
1095
- quoteIsLoading={quoteQuery.isLoading}
1096
- estimatedSeconds={
1097
- quoteQuery.data?.swapDetails.estimated.durationSeconds
1098
- }
1099
- onViewFees={showFees}
1100
- />
1101
- )}
1102
- <Spacer y="md" />
1103
- </div>
1104
-
1105
- {/* Error message */}
1106
- {errorMsg && (
1107
- <div>
1108
- {errorMsg.data?.minimumAmountEth ? (
1109
- <Text color="danger" size="sm" center multiline>
1110
- Minimum amount is{" "}
1111
- {formatNumber(Number(errorMsg.data.minimumAmountEth), 6)}{" "}
1112
- <TokenSymbol
1113
- token={toToken}
1114
- chain={toChain}
1115
- size="sm"
1116
- inline
1117
- color="danger"
1118
- />
1119
- </Text>
1120
- ) : (
1121
- <Text color="danger" size="sm" center multiline>
1122
- {errorMsg.message || defaultMessage}
1123
- </Text>
1124
- )}
1125
- </div>
1126
- )}
1127
-
1128
- {!errorMsg && isNotEnoughBalance && (
1129
- <div>
1130
- <Text color="danger" size="sm" center multiline>
1131
- Not enough funds.
1132
- </Text>
1133
- <Text color="danger" size="sm" center multiline>
1134
- Try a different wallet or token.
1135
- </Text>
1136
- </div>
1137
- )}
1138
-
1139
- {/* Button */}
1140
- {errorMsg?.data?.minimumAmountEth ? (
1141
- <Button
1142
- variant="accent"
1143
- fullWidth
1144
- onClick={() => {
1145
- props.setTokenAmount(
1146
- formatNumber(
1147
- Number(errorMsg.data?.minimumAmountEth),
1148
- 6,
1149
- ).toString(),
1150
- );
1151
- props.setHasEditedAmount(true);
1152
- }}
1153
- >
1154
- Set Minimum
1155
- </Button>
1156
- ) : switchChainRequired &&
1157
- !quoteQuery.isLoading &&
1158
- !isNotEnoughBalance &&
1159
- !quoteQuery.error ? (
1160
- <SwitchNetworkButton
1161
- variant="accent"
1162
- fullWidth
1163
- switchChain={async () => {
1164
- await props.payer.wallet.switchChain(fromChain);
1165
- }}
1166
- />
1167
- ) : (
1168
- <Button
1169
- variant={disableContinue ? "outline" : "accent"}
1170
- fullWidth
1171
- data-disabled={disableContinue}
1172
- disabled={disableContinue}
1173
- onClick={async () => {
1174
- if (!disableContinue) {
1175
- showSwapFlow();
1176
- }
1177
- }}
1178
- gap="xs"
1179
- >
1180
- {quoteQuery.isLoading ? (
1181
- <>
1182
- Getting price quote
1183
- <Spinner size="sm" color="accentText" />
1184
- </>
1185
- ) : (
1186
- "Continue"
1187
- )}
1188
- </Button>
1189
- )}
1190
- </Container>
1191
- );
1192
- }
1193
-
1194
- function FiatScreenContent(props: {
1195
- setScreen: (screen: SelectedScreen) => void;
1196
- tokenAmount: string;
1197
- toToken: ERC20OrNativeToken;
1198
- toChain: Chain;
1199
- selectedCurrency: CurrencyMeta;
1200
- showCurrencySelector: () => void;
1201
- payOptions: PayUIOptions;
1202
- theme: "light" | "dark" | Theme;
1203
- client: ThirdwebClient;
1204
- onDone: () => void;
1205
- isEmbed: boolean;
1206
- payer: PayerInfo;
1207
- setTokenAmount: (amount: string) => void;
1208
- setHasEditedAmount: (hasEdited: boolean) => void;
1209
- }) {
1210
- const {
1211
- toToken,
1212
- tokenAmount,
1213
- payer,
1214
- client,
1215
- setScreen,
1216
- toChain,
1217
- showCurrencySelector,
1218
- selectedCurrency,
1219
- } = props;
1220
- const defaultRecipientAddress = (
1221
- props.payOptions as Extract<PayUIOptions, { mode: "direct_payment" }>
1222
- )?.paymentInfo?.sellerAddress;
1223
- const receiverAddress =
1224
- defaultRecipientAddress || props.payer.account.address;
1225
- const { drawerRef, drawerOverlayRef, isOpen, setIsOpen } = useDrawer();
1226
- const [drawerScreen, setDrawerScreen] = useState<"fees">("fees");
1227
-
1228
- const buyWithFiatOptions = props.payOptions.buyWithFiat;
1229
-
1230
- const fiatQuoteQuery = useBuyWithFiatQuote(
1231
- buyWithFiatOptions !== false && tokenAmount
1232
- ? {
1233
- fromCurrencySymbol: selectedCurrency.shorthand,
1234
- toChainId: toChain.id,
1235
- toAddress: receiverAddress,
1236
- toTokenAddress: isNativeToken(toToken)
1237
- ? NATIVE_TOKEN_ADDRESS
1238
- : toToken.address,
1239
- toAmount: tokenAmount,
1240
- client,
1241
- isTestMode: buyWithFiatOptions?.testMode,
1242
- purchaseData: props.payOptions.purchaseData,
1243
- fromAddress: payer.account.address,
1244
- preferredProvider: buyWithFiatOptions?.preferredProvider,
1245
- }
1246
- : undefined,
1247
- );
1248
-
1249
- function handleSubmit() {
1250
- if (!fiatQuoteQuery.data) {
1251
- return;
1252
- }
1253
-
1254
- const hasTwoSteps = isSwapRequiredPostOnramp(fiatQuoteQuery.data);
1255
- let openedWindow: Window | null = null;
1256
-
1257
- if (!hasTwoSteps) {
1258
- openedWindow = openOnrampPopup(
1259
- fiatQuoteQuery.data.onRampLink,
1260
- typeof props.theme === "string" ? props.theme : props.theme.type,
1261
- );
1262
-
1263
- addPendingTx({
1264
- type: "fiat",
1265
- intentId: fiatQuoteQuery.data.intentId,
1266
- });
1267
- }
1268
-
1269
- setScreen({
1270
- id: "fiat-flow",
1271
- quote: fiatQuoteQuery.data,
1272
- openedWindow,
1273
- });
1274
- }
1275
-
1276
- function showFees() {
1277
- if (!fiatQuoteQuery.data) {
1278
- return;
1279
- }
1280
-
1281
- setDrawerScreen("fees");
1282
- setIsOpen(true);
1283
- }
1284
-
1285
- const disableSubmit = !fiatQuoteQuery.data;
1286
-
1287
- const errorMsg =
1288
- !fiatQuoteQuery.isLoading && fiatQuoteQuery.error
1289
- ? getErrorMessage(fiatQuoteQuery.error)
1290
- : undefined;
1291
-
1292
- return (
1293
- <Container flex="column" gap="md" animate="fadein">
1294
- {isOpen && (
1295
- <>
1296
- <DrawerOverlay ref={drawerOverlayRef} />
1297
- <Drawer ref={drawerRef} close={() => setIsOpen(false)}>
1298
- {drawerScreen === "fees" && fiatQuoteQuery.data && (
1299
- <div>
1300
- <Text size="lg" color="primaryText">
1301
- Fees
1302
- </Text>
1303
-
1304
- <Spacer y="lg" />
1305
- <FiatFees quote={fiatQuoteQuery.data} />
1306
- </div>
1307
- )}
1308
- </Drawer>
1309
- </>
1310
- )}
1311
-
1312
- <div>
1313
- <PayWithCreditCard
1314
- isLoading={fiatQuoteQuery.isLoading}
1315
- value={fiatQuoteQuery.data?.fromCurrencyWithFees.amount}
1316
- client={client}
1317
- currency={selectedCurrency}
1318
- onSelectCurrency={showCurrencySelector}
1319
- />
1320
- {/* Estimated time + View fees button */}
1321
- <EstimatedTimeAndFees
1322
- quoteIsLoading={fiatQuoteQuery.isLoading}
1323
- estimatedSeconds={fiatQuoteQuery.data?.estimatedDurationSeconds}
1324
- onViewFees={showFees}
1325
- />
1326
- <Spacer y="md" />
1327
- </div>
1328
-
1329
- {/* Error message */}
1330
- {errorMsg && (
1331
- <div>
1332
- {errorMsg.data?.minimumAmountEth ? (
1333
- <Text color="danger" size="sm" center multiline>
1334
- Minimum amount is{" "}
1335
- {formatNumber(Number(errorMsg.data.minimumAmountEth), 6)}{" "}
1336
- <TokenSymbol
1337
- token={toToken}
1338
- chain={toChain}
1339
- size="sm"
1340
- inline
1341
- color="danger"
1342
- />
1343
- </Text>
1344
- ) : (
1345
- <Text color="danger" size="sm" center multiline>
1346
- {errorMsg.message || defaultMessage}
1347
- </Text>
1348
- )}
1349
- </div>
1350
- )}
1351
-
1352
- {errorMsg?.data?.minimumAmountEth ? (
1353
- <Button
1354
- variant="accent"
1355
- fullWidth
1356
- onClick={() => {
1357
- props.setTokenAmount(
1358
- formatNumber(
1359
- Number(errorMsg.data?.minimumAmountEth),
1360
- 6,
1361
- ).toString(),
1362
- );
1363
- props.setHasEditedAmount(true);
1364
- }}
1365
- >
1366
- Set Minimum
1367
- </Button>
1368
- ) : (
1369
- <Button
1370
- variant={disableSubmit ? "outline" : "accent"}
1371
- data-disabled={disableSubmit}
1372
- disabled={disableSubmit}
1373
- fullWidth
1374
- onClick={handleSubmit}
1375
- gap="xs"
1376
- >
1377
- {fiatQuoteQuery.isLoading ? (
1378
- <>
1379
- Getting price quote
1380
- <Spinner size="sm" color="accentText" />
1381
- </>
1382
- ) : (
1383
- "Continue"
1384
- )}
1385
- </Button>
1386
- )}
1387
- </Container>
1388
- );
1389
- }
1390
-
1391
953
  function createSupportedTokens(
1392
954
  data: SupportedChainAndTokens,
1393
955
  payOptions: PayUIOptions,
@@ -1478,26 +1040,3 @@ function ChainSelectionScreen(props: {
1478
1040
  />
1479
1041
  );
1480
1042
  }
1481
-
1482
- type ApiError = {
1483
- code: string;
1484
- message?: string;
1485
- data?: {
1486
- minimumAmountUSDCents?: string;
1487
- requestedAmountUSDCents?: string;
1488
- minimumAmountWei?: string;
1489
- minimumAmountEth?: string;
1490
- };
1491
- };
1492
-
1493
- const defaultMessage = "Unable to get price quote";
1494
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
1495
- function getErrorMessage(err: any): ApiError {
1496
- if (typeof err.error === "object") {
1497
- return err.error;
1498
- }
1499
- return {
1500
- code: "UNABLE_TO_GET_PRICE_QUOTE",
1501
- message: defaultMessage,
1502
- };
1503
- }