thirdweb 5.93.1 → 5.93.3

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.
@@ -6,7 +6,7 @@ import type { ThirdwebClient } from "../../../../../../../client/client.js";
6
6
  import { getContract } from "../../../../../../../contract/contract.js";
7
7
  import { allowance } from "../../../../../../../extensions/erc20/__generated__/IERC20/read/allowance.js";
8
8
  import { approve } from "../../../../../../../extensions/erc20/write/approve.js";
9
- import type { BuyWithCryptoQuote } from "../../../../../../../pay/buyWithCrypto/getQuote.js";
9
+ import { getBuyWithCryptoQuote } from "../../../../../../../pay/buyWithCrypto/getQuote.js";
10
10
  import type { BuyWithCryptoStatus } from "../../../../../../../pay/buyWithCrypto/getStatus.js";
11
11
  import type { BuyWithFiatQuote } from "../../../../../../../pay/buyWithFiat/getQuote.js";
12
12
  import {
@@ -17,6 +17,7 @@ import {
17
17
  type OnRampStep,
18
18
  getOnRampSteps,
19
19
  } from "../../../../../../../pay/buyWithFiat/isSwapRequiredPostOnramp.js";
20
+ import type { PayTokenInfo } from "../../../../../../../pay/utils/commonTypes.js";
20
21
  import { sendBatchTransaction } from "../../../../../../../transaction/actions/send-batch-transaction.js";
21
22
  import { sendTransaction } from "../../../../../../../transaction/actions/send-transaction.js";
22
23
  import type { WaitForReceiptOptions } from "../../../../../../../transaction/actions/wait-for-tx-receipt.js";
@@ -28,7 +29,6 @@ import type { Wallet } from "../../../../../../../wallets/interfaces/wallet.js";
28
29
  import { isSmartWallet } from "../../../../../../../wallets/smart/is-smart-wallet.js";
29
30
  import { spacing } from "../../../../../../core/design-system/index.js";
30
31
  import { useChainName } from "../../../../../../core/hooks/others/useChainQuery.js";
31
- import { useBuyWithCryptoQuote } from "../../../../../../core/hooks/pay/useBuyWithCryptoQuote.js";
32
32
  import { useBuyWithCryptoStatus } from "../../../../../../core/hooks/pay/useBuyWithCryptoStatus.js";
33
33
  import { useBuyWithFiatStatus } from "../../../../../../core/hooks/pay/useBuyWithFiatStatus.js";
34
34
  import { useConnectedWallets } from "../../../../../../core/hooks/wallets/useConnectedWallets.js";
@@ -319,20 +319,6 @@ function useOnRampScreenState(props: {
319
319
  // Get quote for current swap/bridge step if needed
320
320
  const previousStep = onRampSteps[currentStepIndex - 1];
321
321
  const currentStep = onRampSteps[currentStepIndex];
322
- const swapQuoteQuery = useBuyWithCryptoQuote(
323
- previousStep && currentStep
324
- ? {
325
- fromChainId: previousStep.token.chainId,
326
- fromTokenAddress: previousStep.token.tokenAddress,
327
- toAmount: currentStep.amount,
328
- toChainId: currentStep.token.chainId,
329
- toTokenAddress: currentStep.token.tokenAddress,
330
- fromAddress: props.payer.account.address,
331
- toAddress: props.payer.account.address,
332
- client: props.client,
333
- }
334
- : undefined,
335
- );
336
322
 
337
323
  // Handle swap execution
338
324
  const swapMutation = useSwapMutation({
@@ -375,9 +361,9 @@ function useOnRampScreenState(props: {
375
361
  status = "completed";
376
362
  } else if (index === currentStepIndex) {
377
363
  // Current step - could be swap or bridge
378
- if (swapQuoteQuery.isLoading || swapMutation.isPending) {
364
+ if (swapMutation.isPending) {
379
365
  status = "pending";
380
- } else if (swapQuoteQuery.error || swapMutation.error) {
366
+ } else if (swapMutation.error) {
381
367
  status = "failed";
382
368
  } else if (swapTxHash) {
383
369
  status = swapStatus;
@@ -418,11 +404,13 @@ function useOnRampScreenState(props: {
418
404
  type: "fiat",
419
405
  intentId: props.quote.intentId,
420
406
  });
421
- } else if (swapQuoteQuery.data && !swapTxHash) {
407
+ } else if (previousStep && currentStep && !swapTxHash) {
422
408
  // Execute swap/bridge
423
409
  try {
424
410
  const result = await swapMutation.mutateAsync({
425
- quote: swapQuoteQuery.data,
411
+ fromToken: previousStep.token,
412
+ toToken: currentStep.token,
413
+ amount: currentStep.amount,
426
414
  });
427
415
  setSwapTxHash({
428
416
  hash: result.transactionHash,
@@ -435,23 +423,22 @@ function useOnRampScreenState(props: {
435
423
  // retry the quote step
436
424
  setSwapTxHash(undefined);
437
425
  swapMutation.reset();
438
- await swapQuoteQuery.refetch();
439
426
  }
440
427
  }, [
441
428
  isDone,
442
429
  currentStepIndex,
443
- swapQuoteQuery.data,
444
430
  swapTxHash,
445
431
  props.quote,
446
432
  props.onDone,
447
433
  swapMutation,
448
434
  props.theme,
449
435
  isFailed,
450
- swapQuoteQuery.refetch,
451
436
  swapMutation.reset,
452
437
  props.client,
453
438
  props.payer.account.address,
454
439
  props.payer.wallet.id,
440
+ currentStep,
441
+ previousStep,
455
442
  ]);
456
443
 
457
444
  // Auto-progress effect
@@ -467,7 +454,6 @@ function useOnRampScreenState(props: {
467
454
  !isFailed &&
468
455
  currentStepIndex > 0 &&
469
456
  currentStepIndex < onRampSteps.length &&
470
- swapQuoteQuery.data &&
471
457
  !swapTxHash
472
458
  ) {
473
459
  handleContinue();
@@ -475,7 +461,6 @@ function useOnRampScreenState(props: {
475
461
  }, [
476
462
  props.isAutoMode,
477
463
  currentStepIndex,
478
- swapQuoteQuery.data,
479
464
  swapTxHash,
480
465
  onRampSteps.length,
481
466
  handleContinue,
@@ -643,9 +628,38 @@ function useSwapMutation(props: {
643
628
  }) {
644
629
  const queryClient = useQueryClient();
645
630
  return useMutation({
646
- mutationFn: async (input: { quote: BuyWithCryptoQuote }) => {
647
- const { quote } = input;
648
- const canBatch = props.payer.account.sendBatchTransaction;
631
+ mutationFn: async (input: {
632
+ fromToken: PayTokenInfo;
633
+ toToken: PayTokenInfo;
634
+ amount: string;
635
+ }) => {
636
+ const { fromToken, toToken, amount } = input;
637
+ const wallet = props.payer.wallet;
638
+
639
+ // in case the wallet is not on the same chain as the fromToken, switch to it
640
+ if (wallet.getChain()?.id !== fromToken.chainId) {
641
+ await wallet.switchChain(getCachedChain(fromToken.chainId));
642
+ }
643
+
644
+ const account = wallet.getAccount();
645
+
646
+ if (!account) {
647
+ throw new Error("Payer wallet has no account");
648
+ }
649
+
650
+ // always get a fresh quote before executing
651
+ const quote = await getBuyWithCryptoQuote({
652
+ fromChainId: fromToken.chainId,
653
+ fromTokenAddress: fromToken.tokenAddress,
654
+ toAmount: amount,
655
+ toChainId: toToken.chainId,
656
+ toTokenAddress: toToken.tokenAddress,
657
+ fromAddress: account.address,
658
+ toAddress: account.address,
659
+ client: props.client,
660
+ });
661
+
662
+ const canBatch = account.sendBatchTransaction;
649
663
  const tokenContract = getContract({
650
664
  client: props.client,
651
665
  address: quote.swapDetails.fromToken.tokenAddress,
@@ -655,14 +669,14 @@ function useSwapMutation(props: {
655
669
  quote.approvalData &&
656
670
  (await allowance({
657
671
  contract: tokenContract,
658
- owner: props.payer.account.address,
672
+ owner: account.address,
659
673
  spender: quote.approvalData.spenderAddress,
660
674
  })) < BigInt(quote.approvalData.amountWei);
661
675
  if (approveTxRequired && quote.approvalData && !canBatch) {
662
676
  trackPayEvent({
663
677
  event: "prompt_swap_approval",
664
678
  client: props.client,
665
- walletAddress: props.payer.account.address,
679
+ walletAddress: account.address,
666
680
  walletType: props.payer.wallet.id,
667
681
  fromToken: quote.swapDetails.fromToken.tokenAddress,
668
682
  fromAmount: quote.swapDetails.fromAmountWei,
@@ -679,7 +693,7 @@ function useSwapMutation(props: {
679
693
  });
680
694
 
681
695
  const tx = await sendTransaction({
682
- account: props.payer.account,
696
+ account,
683
697
  transaction,
684
698
  });
685
699
 
@@ -688,7 +702,7 @@ function useSwapMutation(props: {
688
702
  trackPayEvent({
689
703
  event: "swap_approval_success",
690
704
  client: props.client,
691
- walletAddress: props.payer.account.address,
705
+ walletAddress: account.address,
692
706
  walletType: props.payer.wallet.id,
693
707
  fromToken: quote.swapDetails.fromToken.tokenAddress,
694
708
  fromAmount: quote.swapDetails.fromAmountWei,
@@ -702,7 +716,7 @@ function useSwapMutation(props: {
702
716
  trackPayEvent({
703
717
  event: "prompt_swap_execution",
704
718
  client: props.client,
705
- walletAddress: props.payer.account.address,
719
+ walletAddress: account.address,
706
720
  walletType: props.payer.wallet.id,
707
721
  fromToken: quote.swapDetails.fromToken.tokenAddress,
708
722
  fromAmount: quote.swapDetails.fromAmountWei,
@@ -722,12 +736,12 @@ function useSwapMutation(props: {
722
736
  });
723
737
 
724
738
  _swapTx = await sendBatchTransaction({
725
- account: props.payer.account,
739
+ account,
726
740
  transactions: [approveTx, tx],
727
741
  });
728
742
  } else {
729
743
  _swapTx = await sendTransaction({
730
- account: props.payer.account,
744
+ account,
731
745
  transaction: tx,
732
746
  });
733
747
  }
@@ -737,7 +751,7 @@ function useSwapMutation(props: {
737
751
  trackPayEvent({
738
752
  event: "swap_execution_success",
739
753
  client: props.client,
740
- walletAddress: props.payer.account.address,
754
+ walletAddress: account.address,
741
755
  walletType: props.payer.wallet.id,
742
756
  fromToken: quote.swapDetails.fromToken.tokenAddress,
743
757
  fromAmount: quote.swapDetails.fromAmountWei,
@@ -160,6 +160,19 @@ export function SwapConfirmationScreen(props: {
160
160
  fullWidth
161
161
  disabled={status === "pending"}
162
162
  onClick={async () => {
163
+ const wallet = props.payer.wallet;
164
+
165
+ // in case the wallet is not on the same chain as the fromToken, switch to it
166
+ if (wallet.getChain()?.id !== props.fromChain.id) {
167
+ await wallet.switchChain(props.fromChain);
168
+ }
169
+
170
+ const account = wallet.getAccount();
171
+
172
+ if (!account) {
173
+ throw new Error("Payer wallet has no account");
174
+ }
175
+
163
176
  if (step === "approval" && props.quote.approvalData) {
164
177
  try {
165
178
  setStatus("pending");
@@ -167,8 +180,8 @@ export function SwapConfirmationScreen(props: {
167
180
  trackPayEvent({
168
181
  event: "prompt_swap_approval",
169
182
  client: props.client,
170
- walletAddress: props.payer.account.address,
171
- walletType: props.payer.wallet.id,
183
+ walletAddress: account.address,
184
+ walletType: wallet.id,
172
185
  fromToken: props.quote.swapDetails.fromToken.tokenAddress,
173
186
  fromAmount: props.quote.swapDetails.fromAmountWei,
174
187
  toToken: props.quote.swapDetails.toToken.tokenAddress,
@@ -188,7 +201,7 @@ export function SwapConfirmationScreen(props: {
188
201
  });
189
202
 
190
203
  const tx = await sendTransaction({
191
- account: props.payer.account,
204
+ account: account,
192
205
  transaction,
193
206
  });
194
207
 
@@ -197,8 +210,8 @@ export function SwapConfirmationScreen(props: {
197
210
  trackPayEvent({
198
211
  event: "swap_approval_success",
199
212
  client: props.client,
200
- walletAddress: props.payer.account.address,
201
- walletType: props.payer.wallet.id,
213
+ walletAddress: account.address,
214
+ walletType: wallet.id,
202
215
  fromToken: props.quote.swapDetails.fromToken.tokenAddress,
203
216
  fromAmount: props.quote.swapDetails.fromAmountWei,
204
217
  toToken: props.quote.swapDetails.toToken.tokenAddress,
@@ -221,8 +234,8 @@ export function SwapConfirmationScreen(props: {
221
234
  trackPayEvent({
222
235
  event: "prompt_swap_execution",
223
236
  client: props.client,
224
- walletAddress: props.payer.account.address,
225
- walletType: props.payer.wallet.id,
237
+ walletAddress: account.address,
238
+ walletType: wallet.id,
226
239
  fromToken: props.quote.swapDetails.fromToken.tokenAddress,
227
240
  fromAmount: props.quote.swapDetails.fromAmountWei,
228
241
  toToken: props.quote.swapDetails.toToken.tokenAddress,
@@ -233,7 +246,7 @@ export function SwapConfirmationScreen(props: {
233
246
  const tx = props.quote.transactionRequest;
234
247
  let _swapTx: WaitForReceiptOptions;
235
248
  // check if we can batch approval and swap
236
- const canBatch = props.payer.account.sendBatchTransaction;
249
+ const canBatch = account.sendBatchTransaction;
237
250
  if (
238
251
  canBatch &&
239
252
  props.quote.approvalData &&
@@ -250,12 +263,12 @@ export function SwapConfirmationScreen(props: {
250
263
  });
251
264
 
252
265
  _swapTx = await sendBatchTransaction({
253
- account: props.payer.account,
266
+ account: account,
254
267
  transactions: [approveTx, tx],
255
268
  });
256
269
  } else {
257
270
  _swapTx = await sendTransaction({
258
- account: props.payer.account,
271
+ account: account,
259
272
  transaction: tx,
260
273
  });
261
274
  }
@@ -263,8 +276,8 @@ export function SwapConfirmationScreen(props: {
263
276
  trackPayEvent({
264
277
  event: "swap_execution_success",
265
278
  client: props.client,
266
- walletAddress: props.payer.account.address,
267
- walletType: props.payer.wallet.id,
279
+ walletAddress: account.address,
280
+ walletType: wallet.id,
268
281
  fromToken: props.quote.swapDetails.fromToken.tokenAddress,
269
282
  fromAmount: props.quote.swapDetails.fromAmountWei,
270
283
  toToken: props.quote.swapDetails.toToken.tokenAddress,
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = "5.93.1";
1
+ export const version = "5.93.3";
@@ -264,11 +264,12 @@ async function createSmartAccount(
264
264
  executeOverride: options.overrides?.execute,
265
265
  });
266
266
 
267
+ const chain = getCachedChain(transaction.chainId);
267
268
  const result = await _sendUserOp({
268
269
  executeTx,
269
270
  options: {
270
271
  ...options,
271
- chain: getCachedChain(transaction.chainId),
272
+ chain,
272
273
  accountContract,
273
274
  overrides: {
274
275
  ...options.overrides,
@@ -278,7 +279,7 @@ async function createSmartAccount(
278
279
  });
279
280
  trackTransaction({
280
281
  client: options.client,
281
- chainId: options.chain.id,
282
+ chainId: chain.id,
282
283
  transactionHash: result.transactionHash,
283
284
  walletAddress: options.accountContract.address,
284
285
  walletType: "smart",
@@ -292,17 +293,25 @@ async function createSmartAccount(
292
293
  transactions,
293
294
  executeBatchOverride: options.overrides?.executeBatch,
294
295
  });
296
+ if (transactions.length === 0) {
297
+ throw new Error("No transactions to send");
298
+ }
299
+ const firstTx = transactions[0];
300
+ if (!firstTx) {
301
+ throw new Error("No transactions to send");
302
+ }
303
+ const chain = getCachedChain(firstTx.chainId);
295
304
  const result = await _sendUserOp({
296
305
  executeTx,
297
306
  options: {
298
307
  ...options,
299
- chain: getCachedChain(transactions[0]?.chainId ?? options.chain.id),
308
+ chain,
300
309
  accountContract,
301
310
  },
302
311
  });
303
312
  trackTransaction({
304
313
  client: options.client,
305
- chainId: options.chain.id,
314
+ chainId: chain.id,
306
315
  transactionHash: result.transactionHash,
307
316
  walletAddress: options.accountContract.address,
308
317
  walletType: "smart",