thirdweb 5.34.0-nightly-f6ff5a78fc2d65f0f250b154f1405210ca57ce0a-20240708000345 → 5.34.0-nightly-95c9d3d92406de619cb1e4cccc61b0766dd2a0d4-20240708205331

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 (186) hide show
  1. package/dist/cjs/auth/core/verify-jwt.js +1 -1
  2. package/dist/cjs/auth/core/verify-jwt.js.map +1 -1
  3. package/dist/cjs/auth/verify-hash.js +98 -0
  4. package/dist/cjs/auth/verify-hash.js.map +1 -0
  5. package/dist/cjs/auth/verify-signature.js +5 -60
  6. package/dist/cjs/auth/verify-signature.js.map +1 -1
  7. package/dist/cjs/auth/verify-typed-data.js +80 -0
  8. package/dist/cjs/auth/verify-typed-data.js.map +1 -0
  9. package/dist/cjs/chains/chain-definitions/blast.js +17 -0
  10. package/dist/cjs/chains/chain-definitions/blast.js.map +1 -0
  11. package/dist/cjs/exports/chains.js +3 -1
  12. package/dist/cjs/exports/chains.js.map +1 -1
  13. package/dist/cjs/exports/extensions/erc20.js +3 -1
  14. package/dist/cjs/exports/extensions/erc20.js.map +1 -1
  15. package/dist/cjs/exports/utils.js +10 -1
  16. package/dist/cjs/exports/utils.js.map +1 -1
  17. package/dist/cjs/exports/wallets/smart.js +10 -1
  18. package/dist/cjs/exports/wallets/smart.js.map +1 -1
  19. package/dist/cjs/extensions/erc1271/checkContractWalletSignature.js +1 -0
  20. package/dist/cjs/extensions/erc1271/checkContractWalletSignature.js.map +1 -1
  21. package/dist/cjs/extensions/erc1271/checkContractWalletSignedTypedData.js +1 -0
  22. package/dist/cjs/extensions/erc1271/checkContractWalletSignedTypedData.js.map +1 -1
  23. package/dist/cjs/extensions/erc20/write/transferBatch.js +61 -0
  24. package/dist/cjs/extensions/erc20/write/transferBatch.js.map +1 -0
  25. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +21 -12
  26. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  27. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/PayWIthCreditCard.js +1 -1
  28. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.js +4 -4
  29. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.js +1 -1
  30. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.js +1 -3
  31. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.js.map +1 -1
  32. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.js +1 -4
  33. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.js.map +1 -1
  34. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js +1 -1
  35. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/Fees.js +4 -4
  36. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.js +1 -1
  37. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistoryButton.js +1 -1
  38. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.js +1 -1
  39. package/dist/cjs/utils/hashing/hashTypedData.js +122 -0
  40. package/dist/cjs/utils/hashing/hashTypedData.js.map +1 -0
  41. package/dist/cjs/utils/jwt/decode-jwt.js +2 -2
  42. package/dist/cjs/utils/jwt/decode-jwt.js.map +1 -1
  43. package/dist/cjs/utils/jwt/refresh-jwt.js +1 -1
  44. package/dist/cjs/utils/jwt/refresh-jwt.js.map +1 -1
  45. package/dist/cjs/version.js +1 -1
  46. package/dist/cjs/wallets/smart/index.js +19 -9
  47. package/dist/cjs/wallets/smart/index.js.map +1 -1
  48. package/dist/cjs/wallets/smart/lib/bundler.js +57 -9
  49. package/dist/cjs/wallets/smart/lib/bundler.js.map +1 -1
  50. package/dist/cjs/wallets/smart/lib/calls.js +31 -21
  51. package/dist/cjs/wallets/smart/lib/calls.js.map +1 -1
  52. package/dist/cjs/wallets/smart/lib/paymaster.js +5 -6
  53. package/dist/cjs/wallets/smart/lib/paymaster.js.map +1 -1
  54. package/dist/cjs/wallets/smart/lib/userop.js +45 -21
  55. package/dist/cjs/wallets/smart/lib/userop.js.map +1 -1
  56. package/dist/esm/auth/core/verify-jwt.js +2 -2
  57. package/dist/esm/auth/core/verify-jwt.js.map +1 -1
  58. package/dist/esm/auth/verify-hash.js +95 -0
  59. package/dist/esm/auth/verify-hash.js.map +1 -0
  60. package/dist/esm/auth/verify-signature.js +6 -61
  61. package/dist/esm/auth/verify-signature.js.map +1 -1
  62. package/dist/esm/auth/verify-typed-data.js +77 -0
  63. package/dist/esm/auth/verify-typed-data.js.map +1 -0
  64. package/dist/esm/chains/chain-definitions/blast.js +14 -0
  65. package/dist/esm/chains/chain-definitions/blast.js.map +1 -0
  66. package/dist/esm/exports/chains.js +1 -0
  67. package/dist/esm/exports/chains.js.map +1 -1
  68. package/dist/esm/exports/extensions/erc20.js +1 -0
  69. package/dist/esm/exports/extensions/erc20.js.map +1 -1
  70. package/dist/esm/exports/utils.js +6 -0
  71. package/dist/esm/exports/utils.js.map +1 -1
  72. package/dist/esm/exports/wallets/smart.js +3 -1
  73. package/dist/esm/exports/wallets/smart.js.map +1 -1
  74. package/dist/esm/extensions/erc1271/checkContractWalletSignature.js +1 -0
  75. package/dist/esm/extensions/erc1271/checkContractWalletSignature.js.map +1 -1
  76. package/dist/esm/extensions/erc1271/checkContractWalletSignedTypedData.js +1 -0
  77. package/dist/esm/extensions/erc1271/checkContractWalletSignedTypedData.js.map +1 -1
  78. package/dist/esm/extensions/erc20/write/transferBatch.js +58 -0
  79. package/dist/esm/extensions/erc20/write/transferBatch.js.map +1 -0
  80. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +21 -12
  81. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  82. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/PayWIthCreditCard.js +1 -1
  83. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.js +4 -4
  84. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.js +1 -1
  85. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.js +1 -3
  86. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.js.map +1 -1
  87. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.js +1 -4
  88. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.js.map +1 -1
  89. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js +1 -1
  90. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/Fees.js +4 -4
  91. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.js +1 -1
  92. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistoryButton.js +1 -1
  93. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.js +1 -1
  94. package/dist/esm/utils/hashing/hashTypedData.js +118 -0
  95. package/dist/esm/utils/hashing/hashTypedData.js.map +1 -0
  96. package/dist/esm/utils/jwt/decode-jwt.js +1 -1
  97. package/dist/esm/utils/jwt/decode-jwt.js.map +1 -1
  98. package/dist/esm/utils/jwt/refresh-jwt.js +2 -2
  99. package/dist/esm/utils/jwt/refresh-jwt.js.map +1 -1
  100. package/dist/esm/version.js +1 -1
  101. package/dist/esm/wallets/smart/index.js +19 -9
  102. package/dist/esm/wallets/smart/index.js.map +1 -1
  103. package/dist/esm/wallets/smart/lib/bundler.js +56 -8
  104. package/dist/esm/wallets/smart/lib/bundler.js.map +1 -1
  105. package/dist/esm/wallets/smart/lib/calls.js +31 -21
  106. package/dist/esm/wallets/smart/lib/calls.js.map +1 -1
  107. package/dist/esm/wallets/smart/lib/paymaster.js +5 -6
  108. package/dist/esm/wallets/smart/lib/paymaster.js.map +1 -1
  109. package/dist/esm/wallets/smart/lib/userop.js +46 -22
  110. package/dist/esm/wallets/smart/lib/userop.js.map +1 -1
  111. package/dist/types/auth/verify-hash.d.ts +45 -0
  112. package/dist/types/auth/verify-hash.d.ts.map +1 -0
  113. package/dist/types/auth/verify-signature.d.ts.map +1 -1
  114. package/dist/types/auth/verify-typed-data.d.ts +75 -0
  115. package/dist/types/auth/verify-typed-data.d.ts.map +1 -0
  116. package/dist/types/chains/chain-definitions/blast.d.ts +27 -0
  117. package/dist/types/chains/chain-definitions/blast.d.ts.map +1 -0
  118. package/dist/types/exports/chains.d.ts +1 -0
  119. package/dist/types/exports/chains.d.ts.map +1 -1
  120. package/dist/types/exports/extensions/erc20.d.ts +1 -0
  121. package/dist/types/exports/extensions/erc20.d.ts.map +1 -1
  122. package/dist/types/exports/utils.d.ts +4 -0
  123. package/dist/types/exports/utils.d.ts.map +1 -1
  124. package/dist/types/exports/wallets/smart.d.ts +3 -1
  125. package/dist/types/exports/wallets/smart.d.ts.map +1 -1
  126. package/dist/types/extensions/erc1271/checkContractWalletSignature.d.ts +1 -0
  127. package/dist/types/extensions/erc1271/checkContractWalletSignature.d.ts.map +1 -1
  128. package/dist/types/extensions/erc1271/checkContractWalletSignedTypedData.d.ts +1 -0
  129. package/dist/types/extensions/erc1271/checkContractWalletSignedTypedData.d.ts.map +1 -1
  130. package/dist/types/extensions/erc20/write/transferBatch.d.ts +42 -0
  131. package/dist/types/extensions/erc20/write/transferBatch.d.ts.map +1 -0
  132. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.d.ts.map +1 -1
  133. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.d.ts.map +1 -1
  134. package/dist/types/utils/hashing/hashTypedData.d.ts +17 -0
  135. package/dist/types/utils/hashing/hashTypedData.d.ts.map +1 -0
  136. package/dist/types/utils/jwt/decode-jwt.d.ts +1 -1
  137. package/dist/types/utils/jwt/decode-jwt.d.ts.map +1 -1
  138. package/dist/types/version.d.ts +1 -1
  139. package/dist/types/wallets/smart/index.d.ts.map +1 -1
  140. package/dist/types/wallets/smart/lib/bundler.d.ts +53 -5
  141. package/dist/types/wallets/smart/lib/bundler.d.ts.map +1 -1
  142. package/dist/types/wallets/smart/lib/calls.d.ts +25 -7
  143. package/dist/types/wallets/smart/lib/calls.d.ts.map +1 -1
  144. package/dist/types/wallets/smart/lib/paymaster.d.ts +7 -2
  145. package/dist/types/wallets/smart/lib/paymaster.d.ts.map +1 -1
  146. package/dist/types/wallets/smart/lib/userop.d.ts +15 -4
  147. package/dist/types/wallets/smart/lib/userop.d.ts.map +1 -1
  148. package/dist/types/wallets/smart/types.d.ts +4 -2
  149. package/dist/types/wallets/smart/types.d.ts.map +1 -1
  150. package/package.json +1 -1
  151. package/src/auth/core/verify-jwt.ts +2 -2
  152. package/src/auth/verify-hash.test.ts +66 -0
  153. package/src/auth/verify-hash.ts +126 -0
  154. package/src/auth/verify-signature.ts +6 -77
  155. package/src/auth/verify-typed-data.test.ts +82 -0
  156. package/src/auth/verify-typed-data.ts +110 -0
  157. package/src/chains/chain-definitions/blast.ts +14 -0
  158. package/src/exports/chains.ts +1 -0
  159. package/src/exports/extensions/erc20.ts +4 -0
  160. package/src/exports/utils.ts +8 -0
  161. package/src/exports/wallets/smart.ts +14 -1
  162. package/src/extensions/erc1271/checkContractWalletSignature.ts +1 -0
  163. package/src/extensions/erc1271/checkContractWalletSignedTypedData.ts +1 -0
  164. package/src/extensions/erc20/write/transferBatch.ts +78 -0
  165. package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +42 -12
  166. package/src/react/web/ui/ConnectWallet/screens/Buy/PayWIthCreditCard.tsx +1 -1
  167. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.tsx +5 -5
  168. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.tsx +1 -1
  169. package/src/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.ts +1 -5
  170. package/src/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.ts +1 -6
  171. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.tsx +2 -2
  172. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/Fees.tsx +4 -4
  173. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.tsx +1 -1
  174. package/src/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistoryButton.tsx +1 -1
  175. package/src/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.tsx +1 -1
  176. package/src/utils/hashing/hashTypedData.test.ts +207 -0
  177. package/src/utils/hashing/hashTypedData.ts +210 -0
  178. package/src/utils/jwt/decode-jwt.ts +1 -1
  179. package/src/utils/jwt/refresh-jwt.ts +2 -2
  180. package/src/version.ts +1 -1
  181. package/src/wallets/smart/index.ts +19 -9
  182. package/src/wallets/smart/lib/bundler.ts +56 -9
  183. package/src/wallets/smart/lib/calls.ts +67 -28
  184. package/src/wallets/smart/lib/paymaster.ts +12 -13
  185. package/src/wallets/smart/lib/userop.ts +74 -30
  186. package/src/wallets/smart/types.ts +6 -6
@@ -12,6 +12,7 @@ const MAGIC_VALUE = "0x1626ba7e";
12
12
 
13
13
  /**
14
14
  * Checks if a contract wallet signature is valid.
15
+ * @deprecated Use `verifySignature` instead
15
16
  * @param options - The options for the checkContractWalletSignature function.
16
17
  * @param options.contract - The contract to check the signature against.
17
18
  * @param options.message - The message to check the signature against.
@@ -15,6 +15,7 @@ const MAGIC_VALUE = "0x1626ba7e";
15
15
 
16
16
  /**
17
17
  * Checks if a contract wallet signature is valid.
18
+ * @deprecated Use `verifyTypedData` instead
18
19
  * @param options - The options for the checkContractWalletSignature function.
19
20
  * @param options.contract - The contract to check the signature against.
20
21
  * @param options.message - The message to check the signature against.
@@ -0,0 +1,78 @@
1
+ import type { BaseTransactionOptions } from "../../../transaction/types.js";
2
+ import type { Prettify } from "../../../utils/type-utils.js";
3
+ import { toUnits } from "../../../utils/units.js";
4
+ import { multicall } from "../../common/__generated__/IMulticall/write/multicall.js";
5
+ import { encodeTransfer } from "../__generated__/IERC20/write/transfer.js";
6
+ /**
7
+ * Represents the parameters for a batch transfer operation.
8
+ */
9
+ export type TransferBatchParams = Prettify<{
10
+ batch: Array<
11
+ { to: string } & (
12
+ | {
13
+ amount: number | string;
14
+ }
15
+ | {
16
+ amountWei: bigint;
17
+ }
18
+ )
19
+ >;
20
+ }>;
21
+
22
+ /**
23
+ * Transfers a batch of ERC20 tokens from the sender's address to the specified recipient address.
24
+ * @param options - The options for the batch transfer transaction.
25
+ * @returns A promise that resolves to the prepared transaction.
26
+ * @extension ERC20
27
+ * @example
28
+ * ```ts
29
+ * import { transferBatch } from "thirdweb/extensions/erc20";
30
+ * import { sendTransaction } from "thirdweb";
31
+ *
32
+ * const transaction = transferBatch({
33
+ * contract,
34
+ * batch: [
35
+ * {
36
+ * to: "0x...",
37
+ * amount: 100,
38
+ * },
39
+ * {
40
+ * to: "0x...",
41
+ * amount: "0.1",
42
+ * },
43
+ * ]);
44
+ *
45
+ * await sendTransaction({ transaction, account });
46
+ * ```
47
+ */
48
+ export function transferBatch(
49
+ options: BaseTransactionOptions<TransferBatchParams>,
50
+ ) {
51
+ return multicall({
52
+ contract: options.contract,
53
+ asyncParams: async () => {
54
+ return {
55
+ data: await Promise.all(
56
+ options.batch.map(async (transfer) => {
57
+ let amount: bigint;
58
+ if ("amount" in transfer) {
59
+ // if we need to parse the amount from ether to gwei then we pull in the decimals extension
60
+ const { decimals } = await import("../read/decimals.js");
61
+ // it's OK to call this multiple times because the call is cached
62
+ // if this fails we fall back to `18` decimals
63
+ const d = await decimals(options).catch(() => 18);
64
+ // turn ether into gwei
65
+ amount = toUnits(transfer.amount.toString(), d);
66
+ } else {
67
+ amount = transfer.amountWei;
68
+ }
69
+ return encodeTransfer({
70
+ to: transfer.to,
71
+ value: amount,
72
+ });
73
+ }),
74
+ ),
75
+ };
76
+ },
77
+ });
78
+ }
@@ -141,6 +141,8 @@ function BuyScreenContent(props: BuyScreenContentProps) {
141
141
  id: "main",
142
142
  });
143
143
 
144
+ const [hasEditedAmount, setHasEditedAmount] = useState(false);
145
+
144
146
  // UI selection
145
147
  const {
146
148
  tokenAmount,
@@ -408,6 +410,8 @@ function BuyScreenContent(props: BuyScreenContentProps) {
408
410
  supportedDestinations={supportedDestinations}
409
411
  onBack={props.onBack}
410
412
  theme={props.theme}
413
+ hasEditedAmount={hasEditedAmount}
414
+ setHasEditedAmount={setHasEditedAmount}
411
415
  />
412
416
  )}
413
417
 
@@ -486,6 +490,7 @@ function BuyScreenContent(props: BuyScreenContentProps) {
486
490
  }}
487
491
  payer={payer}
488
492
  setTokenAmount={setTokenAmount}
493
+ setHasEditedAmount={setHasEditedAmount}
489
494
  />
490
495
  )}
491
496
  </TokenSelectedLayout>
@@ -512,8 +517,8 @@ function SelectedTokenInfo(props: {
512
517
  }}
513
518
  >
514
519
  <Container flex="row" gap="xs" center="y">
515
- <Text color="primaryText" data-testid="tokenAmount" size="xxl">
516
- {formatNumber(Number(props.tokenAmount), 5)}
520
+ <Text color="primaryText" data-testid="tokenAmount" size="xl">
521
+ {formatNumber(Number(props.tokenAmount), 6)}
517
522
  </Text>
518
523
 
519
524
  <Container flex="row" gap="xxs" center="y">
@@ -559,6 +564,8 @@ function MainScreen(props: {
559
564
  supportedDestinations: SupportedChainAndTokens;
560
565
  onBack: (() => void) | undefined;
561
566
  theme: "light" | "dark" | Theme;
567
+ hasEditedAmount: boolean;
568
+ setHasEditedAmount: (hasEdited: boolean) => void;
562
569
  }) {
563
570
  const { showPaymentSelection, buyWithCryptoEnabled, buyWithFiatEnabled } =
564
571
  useEnabledPaymentMethods({
@@ -568,7 +575,6 @@ function MainScreen(props: {
568
575
  toToken: props.toToken,
569
576
  });
570
577
 
571
- const [hasEditedAmount, setHasEditedAmount] = useState(false);
572
578
  const {
573
579
  buyForTx,
574
580
  setTokenAmount,
@@ -584,7 +590,7 @@ function MainScreen(props: {
584
590
  const { amountNeeded } = useBuyTxStates({
585
591
  setTokenAmount,
586
592
  buyForTx: buyForTx || null,
587
- hasEditedAmount,
593
+ hasEditedAmount: props.hasEditedAmount,
588
594
  account: payerAccount || null,
589
595
  });
590
596
 
@@ -605,7 +611,7 @@ function MainScreen(props: {
605
611
  <Spacer y="lg" />
606
612
  <BuyForTxUI
607
613
  amountNeeded={String(
608
- formatNumber(Number(toEther(amountNeeded)), 4),
614
+ formatNumber(Number(toEther(amountNeeded)), 6),
609
615
  )}
610
616
  buyForTx={props.buyForTx}
611
617
  client={client}
@@ -619,7 +625,7 @@ function MainScreen(props: {
619
625
  <BuyTokenInput
620
626
  value={tokenAmount}
621
627
  onChange={async (value) => {
622
- setHasEditedAmount(true);
628
+ props.setHasEditedAmount(true);
623
629
  setTokenAmount(value);
624
630
  }}
625
631
  freezeAmount={payOptions.prefillBuy?.allowEdits?.amount === false}
@@ -1094,6 +1100,7 @@ function FiatScreenContent(props: {
1094
1100
  isEmbed: boolean;
1095
1101
  payer: PayerInfo;
1096
1102
  setTokenAmount: (amount: string) => void;
1103
+ setHasEditedAmount: (hasEdited: boolean) => void;
1097
1104
  }) {
1098
1105
  const [receiverAddress, setReceiverAddress] = useState(
1099
1106
  props.payer.account.address,
@@ -1182,18 +1189,27 @@ function FiatScreenContent(props: {
1182
1189
  try {
1183
1190
  if (err.error.code === "MINIMUM_PURCHASE_AMOUNT") {
1184
1191
  const obj = err.error as AmountTooLowError;
1185
-
1186
1192
  const minAmountUSD = obj.data.minimumAmountUSDCents;
1187
1193
  const currentAmountUSD = obj.data.requestedAmountUSDCents;
1194
+
1195
+ // avoid divide by zero
1196
+ // if we can't calculate the minimum amount in # of tokens, don't show the button to set the minimum amount
1197
+ if (obj.data.requestedAmountUSDCents === 0) {
1198
+ return {
1199
+ msg: [
1200
+ "Purchase amount is too low",
1201
+ "Increase the amount and try again",
1202
+ ],
1203
+ };
1204
+ }
1205
+
1188
1206
  const currentAmountToken = Number(props.tokenAmount);
1189
1207
  const minAmountToken =
1190
1208
  (minAmountUSD * currentAmountToken) / currentAmountUSD;
1191
1209
  const minAmountTokenWithBuffer = minAmountToken * 1.2; // 20% buffer
1192
- const formattedNum = formatNumber(minAmountTokenWithBuffer, 3);
1193
1210
 
1194
1211
  return {
1195
- msg: [`Minimum purchase amount is ${formattedNum}`],
1196
- minAmount: formattedNum,
1212
+ minAmount: minAmountTokenWithBuffer,
1197
1213
  };
1198
1214
  }
1199
1215
  } catch {}
@@ -1279,7 +1295,20 @@ function FiatScreenContent(props: {
1279
1295
  {/* Error message */}
1280
1296
  {errorMsg && (
1281
1297
  <div>
1282
- {errorMsg.msg.map((msg) => (
1298
+ {errorMsg.minAmount && (
1299
+ <Text color="danger" size="sm" center multiline>
1300
+ Minimum amount is {formatNumber(errorMsg.minAmount, 6)}{" "}
1301
+ <TokenSymbol
1302
+ token={toToken}
1303
+ chain={toChain}
1304
+ size="sm"
1305
+ inline
1306
+ color="danger"
1307
+ />
1308
+ </Text>
1309
+ )}
1310
+
1311
+ {errorMsg.msg?.map((msg) => (
1283
1312
  <Text color="danger" size="sm" center multiline key={msg}>
1284
1313
  {msg}
1285
1314
  </Text>
@@ -1293,6 +1322,7 @@ function FiatScreenContent(props: {
1293
1322
  fullWidth
1294
1323
  onClick={() => {
1295
1324
  props.setTokenAmount(String(errorMsg.minAmount));
1325
+ props.setHasEditedAmount(true);
1296
1326
  }}
1297
1327
  >
1298
1328
  Set Minimum
@@ -1376,7 +1406,7 @@ function BuyForTxUI(props: {
1376
1406
  <Text size="sm">Your Balance</Text>
1377
1407
  <Container flex="row" gap="xs">
1378
1408
  <Text color="primaryText" size="sm">
1379
- {formatNumber(Number(toEther(props.buyForTx.balance)), 4)}{" "}
1409
+ {formatNumber(Number(toEther(props.buyForTx.balance)), 6)}{" "}
1380
1410
  {props.buyForTx.tokenSymbol}
1381
1411
  </Text>
1382
1412
  <TokenIcon
@@ -82,7 +82,7 @@ export function PayWithCreditCard(props: {
82
82
  <Skeleton width="100px" height={fontSize.lg} />
83
83
  ) : (
84
84
  <Text size="lg" color={props.value ? "primaryText" : "secondaryText"}>
85
- {props.value ? `${formatNumber(Number(props.value), 4)}` : "--"}
85
+ {props.value ? `${formatNumber(Number(props.value), 6)}` : "--"}
86
86
  </Text>
87
87
  )}
88
88
  </div>
@@ -163,7 +163,7 @@ export function FiatSteps(props: {
163
163
  const onRampTokenInfo = (
164
164
  <div>
165
165
  <Text color="primaryText" size="sm">
166
- {formatNumber(Number(onRampTokenAmount), 4)}{" "}
166
+ {formatNumber(Number(onRampTokenAmount), 6)}{" "}
167
167
  <TokenSymbol token={onRampToken} chain={onRampChain} size="sm" inline />
168
168
  </Text>
169
169
  </div>
@@ -203,7 +203,7 @@ export function FiatSteps(props: {
203
203
  textDecoration: "line-through",
204
204
  }}
205
205
  >
206
- {formatNumber(Number(toTokenAmount), 4)}{" "}
206
+ {formatNumber(Number(toTokenAmount), 6)}{" "}
207
207
  <TokenSymbol
208
208
  token={toToken}
209
209
  chain={toChain}
@@ -213,7 +213,7 @@ export function FiatSteps(props: {
213
213
  />
214
214
  </Text>{" "}
215
215
  <Text color="danger" size="sm" inline>
216
- {formatNumber(Number(props.status.destination.amount), 4)}{" "}
216
+ {formatNumber(Number(props.status.destination.amount), 6)}{" "}
217
217
  <TokenSymbol
218
218
  token={{
219
219
  address: props.status.destination.token.tokenAddress,
@@ -231,7 +231,7 @@ export function FiatSteps(props: {
231
231
 
232
232
  const toTokenInfo = partialSuccessToTokenInfo || (
233
233
  <Text color="primaryText" size="sm">
234
- {formatNumber(Number(toTokenAmount), 4)}{" "}
234
+ {formatNumber(Number(toTokenAmount), 6)}{" "}
235
235
  <TokenSymbol token={toToken} chain={toChain} size="sm" inline />
236
236
  </Text>
237
237
  );
@@ -330,7 +330,7 @@ export function FiatSteps(props: {
330
330
  icon: fiatIcon,
331
331
  primaryText: (
332
332
  <Text color="primaryText" size="sm">
333
- {formatNumber(Number(fromCurrencyAmount), 4)} {fromCurrencySymbol}
333
+ {formatNumber(Number(fromCurrencyAmount), 6)} {fromCurrencySymbol}
334
334
  </Text>
335
335
  ),
336
336
  }}
@@ -75,7 +75,7 @@ export function OnRampTxDetailsTable(props: {
75
75
  <Container flex="row" gap="xs" center="y">
76
76
  <currencyMeta.icon size={iconSize.sm} />
77
77
  <Text color="primaryText">
78
- {formatNumber(Number(props.fiat.amount), 4)}{" "}
78
+ {formatNumber(Number(props.fiat.amount), 2)}{" "}
79
79
  {props.fiat.currencySymbol}
80
80
  </Text>
81
81
  </Container>
@@ -1,5 +1,4 @@
1
1
  import { useEffect, useState } from "react";
2
- import { formatNumber } from "../../../../../../../utils/formatNumber.js";
3
2
  import { toEther } from "../../../../../../../utils/units.js";
4
3
  import type { Account } from "../../../../../../../wallets/interfaces/wallet.js";
5
4
  import { getTotalTxCostForBuy } from "../../../../../../core/hooks/transaction/useSendTransaction.js";
@@ -48,10 +47,7 @@ export function useBuyTxStates(options: {
48
47
 
49
48
  if (shouldRefreshTokenAmount) {
50
49
  if (totalCost > buyForTx.balance) {
51
- const _tokenAmount = String(
52
- formatNumber(Number(toEther(totalCost - buyForTx.balance)), 4),
53
- );
54
- setTokenAmount(_tokenAmount);
50
+ setTokenAmount(toEther(totalCost - buyForTx.balance));
55
51
  }
56
52
  }
57
53
  } catch {
@@ -1,7 +1,6 @@
1
1
  import { useState } from "react";
2
2
  import { polygon } from "../../../../../../../chains/chain-definitions/polygon.js";
3
3
  import type { Chain } from "../../../../../../../chains/types.js";
4
- import { formatNumber } from "../../../../../../../utils/formatNumber.js";
5
4
  import { toEther } from "../../../../../../../utils/units.js";
6
5
  import type { PayUIOptions } from "../../../../../../core/hooks/connection/ConnectButtonProps.js";
7
6
  import { useActiveWalletChain } from "../../../../../hooks/wallets/useActiveWalletChain.js";
@@ -24,11 +23,7 @@ export function useUISelectionStates(options: {
24
23
  // buy token amount ---------------------------------------------------------
25
24
  const initialTokenAmount =
26
25
  payOptions.prefillBuy?.amount ||
27
- (buyForTx
28
- ? String(
29
- formatNumber(Number(toEther(buyForTx.cost - buyForTx.balance)), 4),
30
- )
31
- : "");
26
+ (buyForTx ? String(toEther(buyForTx.cost - buyForTx.balance)) : "");
32
27
 
33
28
  const [tokenAmount, setTokenAmount] = useState<string>(initialTokenAmount);
34
29
  const deferredTokenAmount = useDebouncedValue(tokenAmount, 300);
@@ -84,7 +84,7 @@ export function SwapConfirmationScreen(props: {
84
84
  <ConfirmItem label="Pay">
85
85
  <RenderTokenInfo
86
86
  chain={props.fromChain}
87
- amount={String(formatNumber(Number(props.fromAmount), 4))}
87
+ amount={String(formatNumber(Number(props.fromAmount), 6))}
88
88
  symbol={props.fromTokenSymbol || ""}
89
89
  token={props.fromToken}
90
90
  client={props.client}
@@ -95,7 +95,7 @@ export function SwapConfirmationScreen(props: {
95
95
  <ConfirmItem label="Receive">
96
96
  <RenderTokenInfo
97
97
  chain={props.toChain}
98
- amount={String(formatNumber(Number(props.toAmount), 4))}
98
+ amount={String(formatNumber(Number(props.toAmount), 6))}
99
99
  symbol={props.toTokenSymbol}
100
100
  token={props.toToken}
101
101
  client={props.client}
@@ -21,7 +21,7 @@ export function SwapFees(props: {
21
21
  }}
22
22
  >
23
23
  {props.quote.processingFees.map((fee) => {
24
- const feeAmount = formatNumber(Number(fee.amount), 4);
24
+ const feeAmount = formatNumber(Number(fee.amount), 6);
25
25
  return (
26
26
  <Container
27
27
  key={`${fee.token.chainId}_${fee.token.tokenAddress}_${feeAmount}`}
@@ -61,14 +61,14 @@ export function FiatFees(props: {
61
61
  Amount
62
62
  </Text>
63
63
  <Text color="primaryText" inline>
64
- {formatNumber(Number(props.quote.fromCurrency.amount), 4)}{" "}
64
+ {formatNumber(Number(props.quote.fromCurrency.amount), 2)}{" "}
65
65
  {props.quote.fromCurrency.currencySymbol}
66
66
  </Text>
67
67
  </div>
68
68
 
69
69
  {/* Processing Fees */}
70
70
  {props.quote.processingFees.map((fee, i) => {
71
- const feeAmount = formatNumber(Number(fee.amount), 4);
71
+ const feeAmount = formatNumber(Number(fee.amount), 6);
72
72
 
73
73
  return (
74
74
  <div
@@ -106,7 +106,7 @@ export function FiatFees(props: {
106
106
  Total
107
107
  </Text>
108
108
  <Text color="primaryText" inline>
109
- {formatNumber(Number(props.quote.fromCurrencyWithFees.amount), 4)}{" "}
109
+ {formatNumber(Number(props.quote.fromCurrencyWithFees.amount), 6)}{" "}
110
110
  {props.quote.fromCurrencyWithFees.currencySymbol}
111
111
  </Text>
112
112
  </div>
@@ -118,7 +118,7 @@ export function PayWithCrypto(props: {
118
118
  color={props.value ? "primaryText" : "secondaryText"}
119
119
  style={{}}
120
120
  >
121
- {formatNumber(Number(props.value), 4) || "--"}
121
+ {formatNumber(Number(props.value), 6) || "--"}
122
122
  </Text>
123
123
  )}
124
124
 
@@ -79,7 +79,7 @@ export function BuyTxHistoryButton(props: {
79
79
  ? props.txInfo.status.quote.toAmount
80
80
  : props.txInfo.status.quote.estimatedToTokenAmount,
81
81
  ),
82
- 4,
82
+ 6,
83
83
  )}{" "}
84
84
  {props.txInfo.status.quote.toToken.symbol}
85
85
  </Text>{" "}
@@ -46,7 +46,7 @@ export function TokenInfoRow(props: {
46
46
  client={props.client}
47
47
  />
48
48
  <Text color="primaryText">
49
- {formatNumber(Number(props.tokenAmount), 4)} {props.tokenSymbol}
49
+ {formatNumber(Number(props.tokenAmount), 6)} {props.tokenSymbol}
50
50
  </Text>
51
51
  </Container>
52
52
  <Text size="sm">{name}</Text>
@@ -0,0 +1,207 @@
1
+ import { expect, test } from "vitest";
2
+
3
+ import { pad } from "viem";
4
+ import { typedData } from "../../../test/src/typed-data.js";
5
+ import { toHex } from "../encoding/hex.js";
6
+ import { hashTypedData } from "./hashTypedData.js";
7
+
8
+ test("default", () => {
9
+ expect(
10
+ hashTypedData({
11
+ ...typedData.basic,
12
+ primaryType: "Mail",
13
+ }),
14
+ ).toMatchInlineSnapshot(
15
+ '"0x448f54762ef8ecccdc4d19bb7d467161383cd4b271617a8cee05c790eb745d74"',
16
+ );
17
+ });
18
+
19
+ test("complex", () => {
20
+ expect(
21
+ hashTypedData({
22
+ ...typedData.complex,
23
+ primaryType: "Mail",
24
+ }),
25
+ ).toMatchInlineSnapshot(
26
+ '"0x9a74cb859ad30835ffb2da406423233c212cf6dd78e6c2c98b0c9289568954ae"',
27
+ );
28
+ });
29
+
30
+ test("no domain", () => {
31
+ expect(
32
+ hashTypedData({
33
+ ...typedData.complex,
34
+ domain: undefined,
35
+ primaryType: "Mail",
36
+ }),
37
+ ).toMatchInlineSnapshot(
38
+ '"0x14ed1dbbfecbe5de3919f7ea47daafdf3a29dfbb60dd88d85509f79773d503a5"',
39
+ );
40
+ expect(
41
+ hashTypedData({
42
+ ...typedData.complex,
43
+ domain: {},
44
+ primaryType: "Mail",
45
+ }),
46
+ ).toMatchInlineSnapshot(
47
+ '"0x14ed1dbbfecbe5de3919f7ea47daafdf3a29dfbb60dd88d85509f79773d503a5"',
48
+ );
49
+ });
50
+
51
+ test("domain: empty name", () => {
52
+ expect(
53
+ hashTypedData({
54
+ ...typedData.complex,
55
+ domain: { name: "" },
56
+ primaryType: "Mail",
57
+ }),
58
+ ).toMatchInlineSnapshot(
59
+ '"0xc3f4f9ebd774352940f60aebbc83fcee20d0b17eb42bd1b20c91a748001ecb53"',
60
+ );
61
+ });
62
+
63
+ test("minimal valid typed message", () => {
64
+ const hash = hashTypedData({
65
+ types: {
66
+ EIP712Domain: [],
67
+ },
68
+ primaryType: "EIP712Domain",
69
+ domain: {},
70
+ });
71
+
72
+ expect(hash).toMatchInlineSnapshot(
73
+ '"0x8d4a3f4082945b7879e2b55f181c31a77c8c0a464b70669458abbaaf99de4c38"',
74
+ );
75
+ });
76
+
77
+ test("typed message with a domain separator that uses all fields.", () => {
78
+ const hash = hashTypedData({
79
+ types: {
80
+ EIP712Domain: [
81
+ {
82
+ name: "name",
83
+ type: "string",
84
+ },
85
+ {
86
+ name: "version",
87
+ type: "string",
88
+ },
89
+ {
90
+ name: "chainId",
91
+ type: "uint256",
92
+ },
93
+ {
94
+ name: "verifyingContract",
95
+ type: "address",
96
+ },
97
+ {
98
+ name: "salt",
99
+ type: "bytes32",
100
+ },
101
+ ],
102
+ },
103
+ primaryType: "EIP712Domain",
104
+ domain: {
105
+ name: "example.metamask.io",
106
+ version: "1",
107
+ chainId: 1n,
108
+ verifyingContract: "0x0000000000000000000000000000000000000000",
109
+ salt: pad(toHex(new Uint8Array([1, 2, 3])), { dir: "right" }),
110
+ },
111
+ });
112
+
113
+ expect(hash).toMatchInlineSnapshot(
114
+ '"0x54ffed5209a17ac210ef3823740b3852ee9cd518b84ee39f0a3fa7f2f9b4205b"',
115
+ );
116
+ });
117
+
118
+ test("typed message with only custom domain separator fields", () => {
119
+ const hash = hashTypedData({
120
+ types: {
121
+ EIP712Domain: [
122
+ {
123
+ name: "customName",
124
+ type: "string",
125
+ },
126
+ {
127
+ name: "customVersion",
128
+ type: "string",
129
+ },
130
+ {
131
+ name: "customChainId",
132
+ type: "uint256",
133
+ },
134
+ {
135
+ name: "customVerifyingContract",
136
+ type: "address",
137
+ },
138
+ {
139
+ name: "customSalt",
140
+ type: "bytes32",
141
+ },
142
+ {
143
+ name: "extraField",
144
+ type: "string",
145
+ },
146
+ ],
147
+ },
148
+ primaryType: "EIP712Domain",
149
+ domain: {
150
+ customName: "example.metamask.io",
151
+ customVersion: "1",
152
+ customChainId: 1n,
153
+ customVerifyingContract: "0x0000000000000000000000000000000000000000",
154
+ customSalt: pad(toHex(new Uint8Array([1, 2, 3])), { dir: "right" }),
155
+ extraField: "stuff",
156
+ },
157
+ });
158
+
159
+ expect(hash).toMatchInlineSnapshot(
160
+ '"0x3efa3ef0305f56ba5bba62000500e29fe82c5314bca2f958c64e31b2498560f8"',
161
+ );
162
+ });
163
+
164
+ test("typed message with data", () => {
165
+ const hash = hashTypedData({
166
+ types: {
167
+ EIP712Domain: [
168
+ {
169
+ name: "name",
170
+ type: "string",
171
+ },
172
+ {
173
+ name: "version",
174
+ type: "string",
175
+ },
176
+ {
177
+ name: "chainId",
178
+ type: "uint256",
179
+ },
180
+ {
181
+ name: "verifyingContract",
182
+ type: "address",
183
+ },
184
+ {
185
+ name: "salt",
186
+ type: "bytes32",
187
+ },
188
+ ],
189
+ Message: [{ name: "data", type: "string" }],
190
+ },
191
+ primaryType: "Message",
192
+ domain: {
193
+ name: "example.metamask.io",
194
+ version: "1",
195
+ chainId: 1n,
196
+ verifyingContract: "0x0000000000000000000000000000000000000000",
197
+ salt: pad(toHex(new Uint8Array([1, 2, 3])), { dir: "right" }),
198
+ },
199
+ message: {
200
+ data: "Hello!",
201
+ },
202
+ });
203
+
204
+ expect(hash).toMatchInlineSnapshot(
205
+ '"0xd2669f23b7849020ad41bcbff5b51372793f91320e0f901641945568ed7322be"',
206
+ );
207
+ });