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
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ export function SaleContextProvider(props: {
...(vendorError ? { vendorCode: vendorError.code, vendorMessage: vendorError.message || '' } : {}),
});

// eslint-disable-next-line no-console
console.error('[IMTBL]: Sale error', errorType, data);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want to send this to prod?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. We don't show the error message in the UI, but the console logs will at least help developers debug the reason.


viewDispatch({
payload: {
type: ViewActions.UPDATE_VIEW,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export const fetchFundingBalances = async (
onFundingBalance,
getAmountByCurrency,
getIsGasless,
onComplete,
onFundingRequirement,
onUpdateGasFees,
} = params;
Expand Down Expand Up @@ -85,10 +84,6 @@ export const fetchFundingBalances = async (
? undefined
: getGasEstimate();

const handleOnComplete = () => {
onComplete?.(pushToFoundBalances([]));
};

const handleOnFundingRoute = (route) => {
updateFundingBalances(getAlternativeFundingSteps([route], environment));
};
Expand All @@ -99,9 +94,6 @@ export const fetchFundingBalances = async (
transactionOrGasAmount,
routingOptions: { bridge: false, onRamp: false, swap: true },
fundingRouteFullAmount: true,
onComplete: isBaseCurrency(currency.name)
? handleOnComplete
: undefined,
onFundingRoute: isBaseCurrency(currency.name)
? handleOnFundingRoute
: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const useFundingBalances = () => {
>([]);
const [loadingBalances, setLoadingBalances] = useState(false);
const [gasFees, setGasFees] = useState<TokenBalance | undefined>();
const [fundingBalancesError, setFundingBalancesError] = useState<Error | null>(null);

const queryFundingBalances = () => {
if (
Expand All @@ -40,6 +41,7 @@ export const useFundingBalances = () => {
(async () => {
fetching.current = true;
setLoadingBalances(true);
setFundingBalancesError(null);
try {
const results = await fetchFundingBalances({
provider,
Expand All @@ -55,9 +57,6 @@ export const useFundingBalances = () => {
onFundingBalance: (foundBalances) => {
setFundingBalances([...foundBalances]);
},
onComplete: () => {
setLoadingBalances(false);
},
onFundingRequirement: (requirement) => {
setTransactionRequirement(requirement);
},
Expand All @@ -67,9 +66,10 @@ export const useFundingBalances = () => {
});

setFundingBalancesResult(results);
} catch {
setLoadingBalances(false);
} catch (err) {
setFundingBalancesError(err instanceof Error ? err : new Error(String(err)));
} finally {
setLoadingBalances(false);
fetching.current = false;
}
})();
Expand All @@ -79,6 +79,7 @@ export const useFundingBalances = () => {
fundingBalances,
loadingBalances,
fundingBalancesResult,
fundingBalancesError,
transactionRequirement,
gasFees,
queryFundingBalances,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,35 @@ export type ConfigError = {
data?: Record<string, unknown>;
};

/**
* Validates the order quote response before use. Ensures:
* - Currencies are non-empty (empty usually indicates wrong project config or endpoint).
* - Products are non-empty.
* - Every sale item has a matching product in the quote (no missing productIds).
*/
function validateOrderQuote(
config: OrderQuote,
items: SaleItem[],
): { valid: true } | { valid: false; reason: string } {
if (!config.currencies?.length) {
return { valid: false, reason: 'Quote returned no currencies' };
}

const productIds = Object.keys(config.products || {});
if (productIds.length === 0) {
return { valid: false, reason: 'Quote returned no products' };
}

const missing = items.filter((item) => !config.products![item.productId]);
if (missing.length > 0) {
return {
valid: false,
reason: `Quote missing products for: ${missing.map((m) => m.productId).join(', ')}`,
};
}
return { valid: true };
}

export const useQuoteOrder = ({
items,
environment,
Expand All @@ -53,6 +82,13 @@ export const useQuoteOrder = ({
});
};

const setQuoteValidationError = (reason: string) => {
setOrderQuoteError({
type: SaleErrorTypes.SERVICE_BREAKDOWN,
data: { reason: 'Invalid order quote response', error: reason },
});
};

useEffect(() => {
// Set request params
if (!items?.length || !provider) return;
Expand Down Expand Up @@ -110,14 +146,21 @@ export const useQuoteOrder = ({
await response.json(),
preferredCurrency,
);

const validation = validateOrderQuote(config, items);
if (!validation.valid) {
setQuoteValidationError(validation.reason);
return;
}

setOrderQuote(config);
} catch (error) {
setError(errorToString(error));
} finally {
fetching.current = false;
}
})();
}, [environment, environmentId, queryParams]);
}, [environment, environmentId, queryParams, items]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding items to the useEffect dependency array will re-fetch the quote whenever items changes. Was that intentional?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The quote is based on the items, so it should be refetched if those change.


useEffect(() => {
// Set default currency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,21 @@ export function OrderSummary({ subView }: OrderSummaryProps) {
fundingBalances,
loadingBalances,
fundingBalancesResult,
fundingBalancesError,
transactionRequirement,
gasFees,
queryFundingBalances,
} = useFundingBalances();

// If funding balances failed to load, transition to error view
useEffect(() => {
if (!fundingBalancesError) return;
closeHandover();
goToErrorView(SaleErrorTypes.SERVICE_BREAKDOWN, {
error: errorToString(fundingBalancesError),
});
}, [fundingBalancesError, goToErrorView, closeHandover]);

// Initialise funding balances
useEffect(() => {
if (subView !== OrderSummarySubViews.INIT || !fromTokenAddress) return;
Expand Down
Loading