Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fuzzy-suits-wear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---

Fix fiat payments with no wallets connected
151 changes: 80 additions & 71 deletions packages/thirdweb/src/react/core/hooks/useStepExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
/** Prepared quote returned by Bridge.prepare */
request: BridgePrepareRequest;
/** Wallet instance providing getAccount() & sendTransaction */
wallet: Wallet;
wallet?: Wallet;
/** Window adapter for opening on-ramp URLs (web / RN) */
windowAdapter: WindowAdapter;
/** Thirdweb client for API calls */
Expand Down Expand Up @@ -417,89 +417,98 @@
);
}

// Then execute transactions
const account = wallet.getAccount();
if (!account) {
throw new ApiError({
code: "INVALID_INPUT",
message: "Wallet not connected",
statusCode: 400,
});
}

// Start from where we left off, or from the beginning
const startIndex = currentTxIndex ?? 0;

for (let i = startIndex; i < flatTxs.length; i++) {
if (abortController.signal.aborted) {
break;
if (flatTxs.length > 0) {

Check warning on line 420 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L420

Added line #L420 was not covered by tests
// Then execute transactions
if (!wallet) {
throw new ApiError({
code: "INVALID_INPUT",
message: "No wallet provided to execute transactions",
statusCode: 400,
});

Check warning on line 427 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L422-L427

Added lines #L422 - L427 were not covered by tests
}

const currentTx = flatTxs[i];
if (!currentTx) {
continue; // Skip invalid index
const account = wallet.getAccount();
if (!account) {
throw new ApiError({
code: "INVALID_INPUT",
message: "Wallet not connected",
statusCode: 400,
});

Check warning on line 435 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L429-L435

Added lines #L429 - L435 were not covered by tests
}

setCurrentTxIndex(i);
const currentStepData = preparedQuote.steps[currentTx._stepIndex];
if (!currentStepData) {
throw new Error(`Invalid step index: ${currentTx._stepIndex}`);
}
// Start from where we left off, or from the beginning
const startIndex = currentTxIndex ?? 0;

Check warning on line 439 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L439

Added line #L439 was not covered by tests

// switch chain if needed
if (currentTx.chainId !== wallet.getChain()?.id) {
await wallet.switchChain(getCachedChain(currentTx.chainId));
}
for (let i = startIndex; i < flatTxs.length; i++) {
if (abortController.signal.aborted) {
break;
}

Check warning on line 444 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L441-L444

Added lines #L441 - L444 were not covered by tests

// Check if we can batch transactions
const canBatch =
account.sendBatchTransaction !== undefined && i < flatTxs.length - 1; // Not the last transaction

if (canBatch) {
// Find consecutive transactions on the same chain
const batchTxs: FlattenedTx[] = [currentTx];
let j = i + 1;
while (j < flatTxs.length) {
const nextTx = flatTxs[j];
if (!nextTx || nextTx.chainId !== currentTx.chainId) {
break;
}
batchTxs.push(nextTx);
j++;
const currentTx = flatTxs[i];
if (!currentTx) {
continue; // Skip invalid index

Check warning on line 448 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L446-L448

Added lines #L446 - L448 were not covered by tests
}

// Execute batch if we have multiple transactions
if (batchTxs.length > 1) {
await executeBatch(
batchTxs,
account,
completedStatusResults,
abortController.signal,
);

// Mark all batched transactions as completed
for (const tx of batchTxs) {
setCompletedTxs((prev) => new Set(prev).add(tx._index));
setCurrentTxIndex(i);
const currentStepData = preparedQuote.steps[currentTx._stepIndex];
if (!currentStepData) {
throw new Error(`Invalid step index: ${currentTx._stepIndex}`);
}

Check warning on line 455 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L451-L455

Added lines #L451 - L455 were not covered by tests

// switch chain if needed
if (currentTx.chainId !== wallet.getChain()?.id) {
await wallet.switchChain(getCachedChain(currentTx.chainId));
}

Check warning on line 460 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L458-L460

Added lines #L458 - L460 were not covered by tests

// Check if we can batch transactions
const canBatch =
account.sendBatchTransaction !== undefined &&
i < flatTxs.length - 1; // Not the last transaction

Check warning on line 465 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L463-L465

Added lines #L463 - L465 were not covered by tests

if (canBatch) {

Check warning on line 467 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L467

Added line #L467 was not covered by tests
// Find consecutive transactions on the same chain
const batchTxs: FlattenedTx[] = [currentTx];
let j = i + 1;
while (j < flatTxs.length) {
const nextTx = flatTxs[j];
if (!nextTx || nextTx.chainId !== currentTx.chainId) {
break;
}
batchTxs.push(nextTx);
j++;

Check warning on line 477 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L469-L477

Added lines #L469 - L477 were not covered by tests
}

// Skip ahead
i = j - 1;
continue;
// Execute batch if we have multiple transactions
if (batchTxs.length > 1) {
await executeBatch(
batchTxs,
account,
completedStatusResults,
abortController.signal,
);

Check warning on line 487 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L481-L487

Added lines #L481 - L487 were not covered by tests

// Mark all batched transactions as completed
for (const tx of batchTxs) {
setCompletedTxs((prev) => new Set(prev).add(tx._index));
}

Check warning on line 492 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L490-L492

Added lines #L490 - L492 were not covered by tests

// Skip ahead
i = j - 1;
continue;
}

Check warning on line 497 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L495-L497

Added lines #L495 - L497 were not covered by tests
}
}

// Execute single transaction
await executeSingleTx(
currentTx,
account,
completedStatusResults,
abortController.signal,
);
// Execute single transaction
await executeSingleTx(
currentTx,
account,
completedStatusResults,
abortController.signal,
);

Check warning on line 506 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L501-L506

Added lines #L501 - L506 were not covered by tests

// Mark transaction as completed
setCompletedTxs((prev) => new Set(prev).add(currentTx._index));
// Mark transaction as completed
setCompletedTxs((prev) => new Set(prev).add(currentTx._index));
}

Check warning on line 510 in packages/thirdweb/src/react/core/hooks/useStepExecutor.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/useStepExecutor.ts#L509-L510

Added lines #L509 - L510 were not covered by tests
}

// All done - check if we actually completed everything
if (!abortController.signal.aborted) {
setCurrentTxIndex(undefined);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type PaymentMethod =
}
| {
type: "fiat";
payerWallet: Wallet;
payerWallet?: Wallet;
currency: string;
onramp: "stripe" | "coinbase" | "transak";
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,7 @@

{state.value === "execute" &&
state.context.quote &&
state.context.request &&
state.context.selectedPaymentMethod?.payerWallet && (
state.context.request && (

Check warning on line 372 in packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx#L372

Added line #L372 was not covered by tests
<StepRunner
autoStart={true}
client={client}
Expand Down
7 changes: 6 additions & 1 deletion packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@
* Custom label for the main action button.
*/
buttonLabel?: string;

/**
* The receiver address for the purchased funds.
*/
receiverAddress?: Address;
};

// Enhanced UIOptions to handle unsupported token state
Expand Down Expand Up @@ -455,7 +460,7 @@
paymentMethods={props.paymentMethods}
presetOptions={props.presetOptions}
purchaseData={props.purchaseData}
receiverAddress={undefined}
receiverAddress={props.receiverAddress}

Check warning on line 463 in packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx#L463

Added line #L463 was not covered by tests
uiOptions={bridgeDataQuery.data.data}
showThirdwebBranding={props.showThirdwebBranding}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
toChainId: destinationToken.chainId,
toToken: destinationToken.address,
});
return true;

Check warning on line 136 in packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx#L136

Added line #L136 was not covered by tests
},
queryKey: ["loading_quote", paymentMethod.type],
});
Expand Down
2 changes: 1 addition & 1 deletion packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ interface StepRunnerProps {
/**
* Wallet instance for executing transactions
*/
wallet: Wallet;
wallet?: Wallet;

/**
* Thirdweb client for API calls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
: preparedQuote.intent.destinationTokenAddress,
});
}
return true;

Check warning on line 104 in packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx#L104

Added line #L104 was not covered by tests
},
queryKey: ["payment_details", preparedQuote.type],
});
Expand Down Expand Up @@ -239,7 +240,7 @@
receiver={preparedQuote.intent.receiver}
sender={
preparedQuote.intent.sender ||
paymentMethod.payerWallet.getAccount()?.address
paymentMethod.payerWallet?.getAccount()?.address

Check warning on line 243 in packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx#L243

Added line #L243 was not covered by tests
}
toAmount={displayData.destinationAmount}
toToken={displayData.destinationToken}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,17 @@
const handleOnrampProviderSelected = (
provider: "coinbase" | "stripe" | "transak",
) => {
if (!payerWallet) {
onError(new Error("No wallet available for fiat payment"));
const recipientAddress =
receiverAddress || payerWallet?.getAccount()?.address;
if (!recipientAddress) {
onError(new Error("No recipient address available for fiat payment"));

Check warning on line 202 in packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx#L199-L202

Added lines #L199 - L202 were not covered by tests
return;
}

const fiatPaymentMethod: PaymentMethod = {
currency: "USD",
currency: currency || "USD",

Check warning on line 207 in packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx#L207

Added line #L207 was not covered by tests
onramp: provider,
payerWallet, // Default to USD for now
payerWallet,

Check warning on line 209 in packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx#L209

Added line #L209 was not covered by tests
type: "fiat",
};
handlePaymentMethodSelected(fiatPaymentMethod);
Expand Down Expand Up @@ -307,7 +309,9 @@
country={country}
client={client}
onProviderSelected={handleOnrampProviderSelected}
toAddress={receiverAddress || ""}
toAddress={
receiverAddress || payerWallet?.getAccount()?.address || ""

Check warning on line 313 in packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx#L312-L313

Added lines #L312 - L313 were not covered by tests
}
toAmount={destinationAmount}
toChainId={destinationToken.chainId}
toTokenAddress={destinationToken.address}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
props.chain.id,
getTokenAddress(props.token),
deferredTokenAmount,
props.currency,

Check warning on line 39 in packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx#L39

Added line #L39 was not covered by tests
],
});

Expand Down
Loading