thirdweb 5.105.45 → 5.105.47
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.
- package/dist/cjs/react/core/hooks/transaction/useSendTransaction.js +4 -0
- package/dist/cjs/react/core/hooks/transaction/useSendTransaction.js.map +1 -1
- package/dist/cjs/react/core/hooks/useStepExecutor.js +68 -51
- package/dist/cjs/react/core/hooks/useStepExecutor.js.map +1 -1
- package/dist/cjs/react/web/ui/Bridge/BridgeOrchestrator.js +1 -2
- package/dist/cjs/react/web/ui/Bridge/BridgeOrchestrator.js.map +1 -1
- package/dist/cjs/react/web/ui/Bridge/BuyWidget.js +1 -1
- package/dist/cjs/react/web/ui/Bridge/BuyWidget.js.map +1 -1
- package/dist/cjs/react/web/ui/Bridge/QuoteLoader.js +1 -0
- package/dist/cjs/react/web/ui/Bridge/QuoteLoader.js.map +1 -1
- package/dist/cjs/react/web/ui/Bridge/payment-details/PaymentDetails.js +2 -1
- package/dist/cjs/react/web/ui/Bridge/payment-details/PaymentDetails.js.map +1 -1
- package/dist/cjs/react/web/ui/Bridge/payment-selection/PaymentSelection.js +6 -5
- package/dist/cjs/react/web/ui/Bridge/payment-selection/PaymentSelection.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js +1 -0
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/wallets/create-wallet.js +2 -0
- package/dist/cjs/wallets/create-wallet.js.map +1 -1
- package/dist/cjs/wallets/in-app/core/authentication/siwe.js +5 -3
- package/dist/cjs/wallets/in-app/core/authentication/siwe.js.map +1 -1
- package/dist/cjs/wallets/in-app/native/native-connector.js +0 -1
- package/dist/cjs/wallets/in-app/native/native-connector.js.map +1 -1
- package/dist/cjs/wallets/in-app/web/lib/web-connector.js +0 -1
- package/dist/cjs/wallets/in-app/web/lib/web-connector.js.map +1 -1
- package/dist/cjs/wallets/wallet-connect/controller.js +103 -11
- package/dist/cjs/wallets/wallet-connect/controller.js.map +1 -1
- package/dist/esm/react/core/hooks/transaction/useSendTransaction.js +4 -0
- package/dist/esm/react/core/hooks/transaction/useSendTransaction.js.map +1 -1
- package/dist/esm/react/core/hooks/useStepExecutor.js +68 -51
- package/dist/esm/react/core/hooks/useStepExecutor.js.map +1 -1
- package/dist/esm/react/web/ui/Bridge/BridgeOrchestrator.js +1 -2
- package/dist/esm/react/web/ui/Bridge/BridgeOrchestrator.js.map +1 -1
- package/dist/esm/react/web/ui/Bridge/BuyWidget.js +1 -1
- package/dist/esm/react/web/ui/Bridge/BuyWidget.js.map +1 -1
- package/dist/esm/react/web/ui/Bridge/QuoteLoader.js +1 -0
- package/dist/esm/react/web/ui/Bridge/QuoteLoader.js.map +1 -1
- package/dist/esm/react/web/ui/Bridge/payment-details/PaymentDetails.js +2 -1
- package/dist/esm/react/web/ui/Bridge/payment-details/PaymentDetails.js.map +1 -1
- package/dist/esm/react/web/ui/Bridge/payment-selection/PaymentSelection.js +6 -5
- package/dist/esm/react/web/ui/Bridge/payment-selection/PaymentSelection.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js +1 -0
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/wallets/create-wallet.js +2 -0
- package/dist/esm/wallets/create-wallet.js.map +1 -1
- package/dist/esm/wallets/in-app/core/authentication/siwe.js +5 -3
- package/dist/esm/wallets/in-app/core/authentication/siwe.js.map +1 -1
- package/dist/esm/wallets/in-app/native/native-connector.js +0 -1
- package/dist/esm/wallets/in-app/native/native-connector.js.map +1 -1
- package/dist/esm/wallets/in-app/web/lib/web-connector.js +0 -1
- package/dist/esm/wallets/in-app/web/lib/web-connector.js.map +1 -1
- package/dist/esm/wallets/wallet-connect/controller.js +103 -11
- package/dist/esm/wallets/wallet-connect/controller.js.map +1 -1
- package/dist/types/react/core/hooks/transaction/useSendTransaction.d.ts.map +1 -1
- package/dist/types/react/core/hooks/useStepExecutor.d.ts +1 -1
- package/dist/types/react/core/hooks/useStepExecutor.d.ts.map +1 -1
- package/dist/types/react/core/machines/paymentMachine.d.ts +1 -1
- package/dist/types/react/core/machines/paymentMachine.d.ts.map +1 -1
- package/dist/types/react/web/ui/Bridge/BridgeOrchestrator.d.ts.map +1 -1
- package/dist/types/react/web/ui/Bridge/BuyWidget.d.ts +4 -0
- package/dist/types/react/web/ui/Bridge/BuyWidget.d.ts.map +1 -1
- package/dist/types/react/web/ui/Bridge/QuoteLoader.d.ts.map +1 -1
- package/dist/types/react/web/ui/Bridge/StepRunner.d.ts +1 -1
- package/dist/types/react/web/ui/Bridge/StepRunner.d.ts.map +1 -1
- package/dist/types/react/web/ui/Bridge/payment-details/PaymentDetails.d.ts.map +1 -1
- package/dist/types/react/web/ui/Bridge/payment-selection/PaymentSelection.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/wallets/create-wallet.d.ts.map +1 -1
- package/dist/types/wallets/in-app/core/authentication/siwe.d.ts +0 -2
- package/dist/types/wallets/in-app/core/authentication/siwe.d.ts.map +1 -1
- package/dist/types/wallets/in-app/native/native-connector.d.ts.map +1 -1
- package/dist/types/wallets/in-app/web/lib/web-connector.d.ts.map +1 -1
- package/dist/types/wallets/wallet-connect/controller.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/extensions/erc721/read/getNFT.test.ts +1 -1
- package/src/react/core/hooks/transaction/useSendTransaction.ts +5 -0
- package/src/react/core/hooks/useStepExecutor.ts +88 -71
- package/src/react/core/machines/paymentMachine.ts +1 -1
- package/src/react/web/ui/Bridge/BridgeOrchestrator.tsx +1 -2
- package/src/react/web/ui/Bridge/BuyWidget.tsx +6 -1
- package/src/react/web/ui/Bridge/QuoteLoader.tsx +1 -0
- package/src/react/web/ui/Bridge/StepRunner.tsx +1 -1
- package/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx +2 -1
- package/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx +9 -5
- package/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx +1 -0
- package/src/version.ts +1 -1
- package/src/wallets/create-wallet.ts +2 -0
- package/src/wallets/in-app/core/authentication/siwe.ts +5 -5
- package/src/wallets/in-app/native/native-connector.ts +0 -1
- package/src/wallets/in-app/web/lib/web-connector.test.ts +0 -1
- package/src/wallets/in-app/web/lib/web-connector.ts +0 -1
- package/src/wallets/wallet-connect/controller.ts +117 -14
@@ -38,7 +38,7 @@ interface StepExecutorOptions {
|
|
38
38
|
/** Prepared quote returned by Bridge.prepare */
|
39
39
|
request: BridgePrepareRequest;
|
40
40
|
/** Wallet instance providing getAccount() & sendTransaction */
|
41
|
-
wallet
|
41
|
+
wallet?: Wallet;
|
42
42
|
/** Window adapter for opening on-ramp URLs (web / RN) */
|
43
43
|
windowAdapter: WindowAdapter;
|
44
44
|
/** Thirdweb client for API calls */
|
@@ -408,6 +408,14 @@ export function useStepExecutor(
|
|
408
408
|
abortControllerRef.current = abortController;
|
409
409
|
|
410
410
|
try {
|
411
|
+
if (flatTxs.length > 0 && !wallet) {
|
412
|
+
throw new ApiError({
|
413
|
+
code: "INVALID_INPUT",
|
414
|
+
message: "No wallet provided to execute transactions",
|
415
|
+
statusCode: 400,
|
416
|
+
});
|
417
|
+
}
|
418
|
+
|
411
419
|
// Execute onramp first if configured and not already completed
|
412
420
|
if (preparedQuote.type === "onramp" && onrampStatus === "pending") {
|
413
421
|
await executeOnramp(
|
@@ -417,89 +425,98 @@ export function useStepExecutor(
|
|
417
425
|
);
|
418
426
|
}
|
419
427
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
}
|
429
|
-
|
430
|
-
// Start from where we left off, or from the beginning
|
431
|
-
const startIndex = currentTxIndex ?? 0;
|
432
|
-
|
433
|
-
for (let i = startIndex; i < flatTxs.length; i++) {
|
434
|
-
if (abortController.signal.aborted) {
|
435
|
-
break;
|
428
|
+
if (flatTxs.length > 0) {
|
429
|
+
// Then execute transactions
|
430
|
+
if (!wallet) {
|
431
|
+
throw new ApiError({
|
432
|
+
code: "INVALID_INPUT",
|
433
|
+
message: "No wallet provided to execute transactions",
|
434
|
+
statusCode: 400,
|
435
|
+
});
|
436
436
|
}
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
437
|
+
const account = wallet.getAccount();
|
438
|
+
if (!account) {
|
439
|
+
throw new ApiError({
|
440
|
+
code: "INVALID_INPUT",
|
441
|
+
message: "Wallet not connected",
|
442
|
+
statusCode: 400,
|
443
|
+
});
|
441
444
|
}
|
442
445
|
|
443
|
-
|
444
|
-
const
|
445
|
-
if (!currentStepData) {
|
446
|
-
throw new Error(`Invalid step index: ${currentTx._stepIndex}`);
|
447
|
-
}
|
446
|
+
// Start from where we left off, or from the beginning
|
447
|
+
const startIndex = currentTxIndex ?? 0;
|
448
448
|
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
449
|
+
for (let i = startIndex; i < flatTxs.length; i++) {
|
450
|
+
if (abortController.signal.aborted) {
|
451
|
+
break;
|
452
|
+
}
|
453
453
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
const
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
j++;
|
454
|
+
const currentTx = flatTxs[i];
|
455
|
+
if (!currentTx) {
|
456
|
+
continue; // Skip invalid index
|
457
|
+
}
|
458
|
+
|
459
|
+
setCurrentTxIndex(i);
|
460
|
+
const currentStepData = preparedQuote.steps[currentTx._stepIndex];
|
461
|
+
if (!currentStepData) {
|
462
|
+
throw new Error(`Invalid step index: ${currentTx._stepIndex}`);
|
463
|
+
}
|
464
|
+
|
465
|
+
// switch chain if needed
|
466
|
+
if (currentTx.chainId !== wallet.getChain()?.id) {
|
467
|
+
await wallet.switchChain(getCachedChain(currentTx.chainId));
|
469
468
|
}
|
470
469
|
|
471
|
-
//
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
470
|
+
// Check if we can batch transactions
|
471
|
+
const canBatch =
|
472
|
+
account.sendBatchTransaction !== undefined &&
|
473
|
+
i < flatTxs.length - 1; // Not the last transaction
|
474
|
+
|
475
|
+
if (canBatch) {
|
476
|
+
// Find consecutive transactions on the same chain
|
477
|
+
const batchTxs: FlattenedTx[] = [currentTx];
|
478
|
+
let j = i + 1;
|
479
|
+
while (j < flatTxs.length) {
|
480
|
+
const nextTx = flatTxs[j];
|
481
|
+
if (!nextTx || nextTx.chainId !== currentTx.chainId) {
|
482
|
+
break;
|
483
|
+
}
|
484
|
+
batchTxs.push(nextTx);
|
485
|
+
j++;
|
483
486
|
}
|
484
487
|
|
485
|
-
//
|
486
|
-
|
487
|
-
|
488
|
+
// Execute batch if we have multiple transactions
|
489
|
+
if (batchTxs.length > 1) {
|
490
|
+
await executeBatch(
|
491
|
+
batchTxs,
|
492
|
+
account,
|
493
|
+
completedStatusResults,
|
494
|
+
abortController.signal,
|
495
|
+
);
|
496
|
+
|
497
|
+
// Mark all batched transactions as completed
|
498
|
+
for (const tx of batchTxs) {
|
499
|
+
setCompletedTxs((prev) => new Set(prev).add(tx._index));
|
500
|
+
}
|
501
|
+
|
502
|
+
// Skip ahead
|
503
|
+
i = j - 1;
|
504
|
+
continue;
|
505
|
+
}
|
488
506
|
}
|
489
|
-
}
|
490
507
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
508
|
+
// Execute single transaction
|
509
|
+
await executeSingleTx(
|
510
|
+
currentTx,
|
511
|
+
account,
|
512
|
+
completedStatusResults,
|
513
|
+
abortController.signal,
|
514
|
+
);
|
498
515
|
|
499
|
-
|
500
|
-
|
516
|
+
// Mark transaction as completed
|
517
|
+
setCompletedTxs((prev) => new Set(prev).add(currentTx._index));
|
518
|
+
}
|
501
519
|
}
|
502
|
-
|
503
520
|
// All done - check if we actually completed everything
|
504
521
|
if (!abortController.signal.aborted) {
|
505
522
|
setCurrentTxIndex(undefined);
|
@@ -369,8 +369,7 @@ export function BridgeOrchestrator({
|
|
369
369
|
|
370
370
|
{state.value === "execute" &&
|
371
371
|
state.context.quote &&
|
372
|
-
state.context.request &&
|
373
|
-
state.context.selectedPaymentMethod?.payerWallet && (
|
372
|
+
state.context.request && (
|
374
373
|
<StepRunner
|
375
374
|
autoStart={true}
|
376
375
|
client={client}
|
@@ -193,6 +193,11 @@ export type BuyWidgetProps = {
|
|
193
193
|
* Custom label for the main action button.
|
194
194
|
*/
|
195
195
|
buttonLabel?: string;
|
196
|
+
|
197
|
+
/**
|
198
|
+
* The receiver address for the purchased funds.
|
199
|
+
*/
|
200
|
+
receiverAddress?: Address;
|
196
201
|
};
|
197
202
|
|
198
203
|
// Enhanced UIOptions to handle unsupported token state
|
@@ -455,7 +460,7 @@ export function BuyWidget(props: BuyWidgetProps) {
|
|
455
460
|
paymentMethods={props.paymentMethods}
|
456
461
|
presetOptions={props.presetOptions}
|
457
462
|
purchaseData={props.purchaseData}
|
458
|
-
receiverAddress={
|
463
|
+
receiverAddress={props.receiverAddress}
|
459
464
|
uiOptions={bridgeDataQuery.data.data}
|
460
465
|
showThirdwebBranding={props.showThirdwebBranding}
|
461
466
|
/>
|
@@ -101,6 +101,7 @@ export function PaymentDetails({
|
|
101
101
|
: preparedQuote.intent.destinationTokenAddress,
|
102
102
|
});
|
103
103
|
}
|
104
|
+
return true;
|
104
105
|
},
|
105
106
|
queryKey: ["payment_details", preparedQuote.type],
|
106
107
|
});
|
@@ -239,7 +240,7 @@ export function PaymentDetails({
|
|
239
240
|
receiver={preparedQuote.intent.receiver}
|
240
241
|
sender={
|
241
242
|
preparedQuote.intent.sender ||
|
242
|
-
paymentMethod.payerWallet
|
243
|
+
paymentMethod.payerWallet?.getAccount()?.address
|
243
244
|
}
|
244
245
|
toAmount={displayData.destinationAmount}
|
245
246
|
toToken={displayData.destinationToken}
|
@@ -196,15 +196,17 @@ export function PaymentSelection({
|
|
196
196
|
const handleOnrampProviderSelected = (
|
197
197
|
provider: "coinbase" | "stripe" | "transak",
|
198
198
|
) => {
|
199
|
-
|
200
|
-
|
199
|
+
const recipientAddress =
|
200
|
+
receiverAddress || payerWallet?.getAccount()?.address;
|
201
|
+
if (!recipientAddress) {
|
202
|
+
onError(new Error("No recipient address available for fiat payment"));
|
201
203
|
return;
|
202
204
|
}
|
203
205
|
|
204
206
|
const fiatPaymentMethod: PaymentMethod = {
|
205
|
-
currency: "USD",
|
207
|
+
currency: currency || "USD",
|
206
208
|
onramp: provider,
|
207
|
-
payerWallet,
|
209
|
+
payerWallet,
|
208
210
|
type: "fiat",
|
209
211
|
};
|
210
212
|
handlePaymentMethodSelected(fiatPaymentMethod);
|
@@ -307,7 +309,9 @@ export function PaymentSelection({
|
|
307
309
|
country={country}
|
308
310
|
client={client}
|
309
311
|
onProviderSelected={handleOnrampProviderSelected}
|
310
|
-
toAddress={
|
312
|
+
toAddress={
|
313
|
+
receiverAddress || payerWallet?.getAccount()?.address || ""
|
314
|
+
}
|
311
315
|
toAmount={destinationAmount}
|
312
316
|
toChainId={destinationToken.chainId}
|
313
317
|
toTokenAddress={destinationToken.address}
|
package/src/version.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const version = "5.105.
|
1
|
+
export const version = "5.105.47";
|
@@ -483,6 +483,8 @@ export function createWallet<const ID extends WalletId>(
|
|
483
483
|
id,
|
484
484
|
subscribe: emitter.subscribe,
|
485
485
|
switchChain: async (c) => {
|
486
|
+
// TODO: this should actually throw an error if the chain switch fails
|
487
|
+
// but our useSwitchActiveWalletChain hook currently doesn't handle this
|
486
488
|
try {
|
487
489
|
await handleSwitchChain(c);
|
488
490
|
chain = c;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { signLoginPayload } from "../../../../auth/core/sign-login-payload.js";
|
2
2
|
import type { LoginPayload } from "../../../../auth/core/types.js";
|
3
|
-
import
|
3
|
+
import { getCachedChain } from "../../../../chains/utils.js";
|
4
4
|
import type { ThirdwebClient } from "../../../../client/client.js";
|
5
5
|
import { getClientFetch } from "../../../../utils/fetch.js";
|
6
6
|
import { stringify } from "../../../../utils/json.js";
|
@@ -14,14 +14,14 @@ import type { AuthStoredTokenWithCookieReturnType } from "./types.js";
|
|
14
14
|
*/
|
15
15
|
export async function siweAuthenticate(args: {
|
16
16
|
wallet: Wallet;
|
17
|
-
chain: Chain;
|
18
17
|
client: ThirdwebClient;
|
19
18
|
ecosystem?: Ecosystem;
|
20
19
|
}): Promise<AuthStoredTokenWithCookieReturnType> {
|
21
|
-
const { wallet,
|
20
|
+
const { wallet, client, ecosystem } = args;
|
21
|
+
const siweChain = getCachedChain(1); // always use mainnet for SIWE for wide wallet compatibility
|
22
22
|
// only connect if the wallet doesn't already have an account
|
23
23
|
const account =
|
24
|
-
wallet.getAccount() || (await wallet.connect({ chain, client }));
|
24
|
+
wallet.getAccount() || (await wallet.connect({ chain: siweChain, client }));
|
25
25
|
const clientFetch = getClientFetch(client, ecosystem);
|
26
26
|
|
27
27
|
const payload = await (async () => {
|
@@ -31,7 +31,7 @@ export async function siweAuthenticate(args: {
|
|
31
31
|
ecosystem: args.ecosystem,
|
32
32
|
});
|
33
33
|
const res = await clientFetch(
|
34
|
-
`${path}&address=${account.address}&chainId=${
|
34
|
+
`${path}&address=${account.address}&chainId=${siweChain.id}`,
|
35
35
|
);
|
36
36
|
|
37
37
|
if (!res.ok) throw new Error("Failed to generate SIWE login payload");
|
@@ -132,7 +132,7 @@ export async function connectWC(
|
|
132
132
|
...(wcOptions?.pairingTopic
|
133
133
|
? { pairingTopic: wcOptions?.pairingTopic }
|
134
134
|
: {}),
|
135
|
-
|
135
|
+
optionalNamespaces: {
|
136
136
|
[NAMESPACE]: {
|
137
137
|
chains: chainsToRequest,
|
138
138
|
events: ["chainChanged", "accountsChanged"],
|
@@ -157,14 +157,8 @@ export async function connectWC(
|
|
157
157
|
);
|
158
158
|
const currentChainId = chainsToRequest[0]?.split(":")[1] || 1;
|
159
159
|
const providerChainId = normalizeChainId(currentChainId);
|
160
|
-
const
|
161
|
-
|
162
|
-
method: "eth_requestAccounts",
|
163
|
-
params: [],
|
164
|
-
},
|
165
|
-
`eip155:${providerChainId}`,
|
166
|
-
);
|
167
|
-
const address = accounts[0];
|
160
|
+
const account = firstAccountOn(provider.session, `eip155:1`); // grab the address from mainnet
|
161
|
+
const address = account;
|
168
162
|
if (!address) {
|
169
163
|
throw new Error("No accounts found on provider.");
|
170
164
|
}
|
@@ -202,6 +196,109 @@ export async function connectWC(
|
|
202
196
|
);
|
203
197
|
}
|
204
198
|
|
199
|
+
async function ensureTargetChain(
|
200
|
+
provider: Awaited<ReturnType<typeof initProvider>>,
|
201
|
+
chain: Chain,
|
202
|
+
walletInfo: WalletInfo,
|
203
|
+
) {
|
204
|
+
if (!provider.session) {
|
205
|
+
throw new Error("No session found on provider.");
|
206
|
+
}
|
207
|
+
const TARGET_CAIP = `eip155:${chain.id}`;
|
208
|
+
const TARGET_HEX = numberToHex(chain.id);
|
209
|
+
|
210
|
+
// Fast path: already enabled
|
211
|
+
if (hasChainEnabled(provider.session, TARGET_CAIP)) {
|
212
|
+
provider.setDefaultChain(TARGET_CAIP);
|
213
|
+
return;
|
214
|
+
}
|
215
|
+
|
216
|
+
// 1) Try switch
|
217
|
+
try {
|
218
|
+
await requestAndOpenWallet({
|
219
|
+
provider,
|
220
|
+
payload: {
|
221
|
+
method: "wallet_switchEthereumChain",
|
222
|
+
params: [{ chainId: TARGET_HEX }],
|
223
|
+
},
|
224
|
+
chain: TARGET_CAIP, // route to target
|
225
|
+
walletInfo,
|
226
|
+
});
|
227
|
+
provider.setDefaultChain(TARGET_CAIP);
|
228
|
+
return;
|
229
|
+
} catch (err: any) {
|
230
|
+
const code = err?.code ?? err?.data?.originalError?.code;
|
231
|
+
// 4001 user rejected; stop
|
232
|
+
if (code === 4001) throw new Error("User rejected chain switch");
|
233
|
+
// fall through on 4902 or unknown -> try add
|
234
|
+
}
|
235
|
+
|
236
|
+
// 2) Add the chain via any chain we already have
|
237
|
+
const routeChain = anyRoutableChain(provider.session);
|
238
|
+
if (!routeChain)
|
239
|
+
throw new Error("No routable chain to send wallet_addEthereumChain");
|
240
|
+
|
241
|
+
try {
|
242
|
+
await requestAndOpenWallet({
|
243
|
+
provider,
|
244
|
+
payload: {
|
245
|
+
method: "wallet_addEthereumChain",
|
246
|
+
params: [
|
247
|
+
{
|
248
|
+
chainId: TARGET_HEX,
|
249
|
+
chainName: chain.name,
|
250
|
+
nativeCurrency: chain.nativeCurrency,
|
251
|
+
rpcUrls: [chain.rpc],
|
252
|
+
blockExplorerUrls: [chain.blockExplorers?.[0]?.url ?? ""],
|
253
|
+
},
|
254
|
+
],
|
255
|
+
},
|
256
|
+
chain: routeChain, // route via known-good chain, not the target
|
257
|
+
walletInfo,
|
258
|
+
});
|
259
|
+
} catch (err: any) {
|
260
|
+
const code = err?.code ?? err?.data?.originalError?.code;
|
261
|
+
if (code === 4001) throw new Error("User rejected add chain");
|
262
|
+
throw new Error(`Add chain failed: ${err?.message || String(err)}`);
|
263
|
+
}
|
264
|
+
|
265
|
+
// 3) Re-try switch after add
|
266
|
+
await requestAndOpenWallet({
|
267
|
+
provider,
|
268
|
+
payload: {
|
269
|
+
method: "wallet_switchEthereumChain",
|
270
|
+
params: [{ chainId: TARGET_HEX }],
|
271
|
+
},
|
272
|
+
chain: TARGET_CAIP,
|
273
|
+
walletInfo,
|
274
|
+
});
|
275
|
+
provider.setDefaultChain(TARGET_CAIP);
|
276
|
+
|
277
|
+
// 4) Verify enablement
|
278
|
+
if (!hasChainEnabled(provider.session, TARGET_CAIP)) {
|
279
|
+
throw new Error("Target chain still not enabled by wallet");
|
280
|
+
}
|
281
|
+
}
|
282
|
+
|
283
|
+
type WCSession = Awaited<ReturnType<typeof UniversalProvider.init>>["session"];
|
284
|
+
|
285
|
+
function getNS(session: WCSession) {
|
286
|
+
return session?.namespaces?.eip155;
|
287
|
+
}
|
288
|
+
function hasChainEnabled(session: WCSession, caip: string) {
|
289
|
+
const ns = getNS(session);
|
290
|
+
return !!ns?.accounts?.some((a) => a.startsWith(`${caip}:`));
|
291
|
+
}
|
292
|
+
function firstAccountOn(session: WCSession, caip: string): string | null {
|
293
|
+
const ns = getNS(session);
|
294
|
+
const hit = ns?.accounts?.find((a) => a.startsWith(`${caip}:`));
|
295
|
+
return hit ? (hit.split(":")[2] ?? null) : null;
|
296
|
+
}
|
297
|
+
function anyRoutableChain(session: WCSession): string | null {
|
298
|
+
const ns = getNS(session);
|
299
|
+
return ns?.accounts?.[0]?.split(":")?.slice(0, 2)?.join(":") ?? null; // e.g. "eip155:1"
|
300
|
+
}
|
301
|
+
|
205
302
|
/**
|
206
303
|
* Auto connect to already connected wallet connect session.
|
207
304
|
* @internal
|
@@ -545,14 +642,17 @@ function onConnect(
|
|
545
642
|
account,
|
546
643
|
chain,
|
547
644
|
disconnect,
|
548
|
-
(newChain) => switchChainWC(provider, newChain),
|
645
|
+
(newChain) => switchChainWC(provider, newChain, walletInfo),
|
549
646
|
];
|
550
647
|
}
|
551
648
|
|
552
|
-
async function switchChainWC(
|
553
|
-
|
649
|
+
async function switchChainWC(
|
650
|
+
provider: WCProvider,
|
651
|
+
chain: Chain,
|
652
|
+
walletInfo: WalletInfo,
|
653
|
+
) {
|
554
654
|
try {
|
555
|
-
provider
|
655
|
+
await ensureTargetChain(provider, chain, walletInfo);
|
556
656
|
} catch (error) {
|
557
657
|
const message =
|
558
658
|
typeof error === "string" ? error : (error as ProviderRpcError)?.message;
|
@@ -605,7 +705,10 @@ function getChainsToRequest(options: {
|
|
605
705
|
chainIds.push(chain.id);
|
606
706
|
}
|
607
707
|
|
608
|
-
|
708
|
+
// always include mainnet
|
709
|
+
// many wallets only support a handful of chains, but mainnet is always supported
|
710
|
+
// we will add additional chains in switchChain if needed
|
711
|
+
if (!chainIds.includes(1)) {
|
609
712
|
rpcMap[1] = getCachedChain(1).rpc;
|
610
713
|
chainIds.push(1);
|
611
714
|
}
|