Skip to content
Draft
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 @@ -15,6 +15,7 @@
} from '$eth/stores/eth-fee.store';
import type { ProgressStep } from '$eth/types/send';
import { isTokenErc20 } from '$eth/utils/erc20.utils';
import { toastEthereumTransactionError } from '$eth/utils/eth-error.utils';
import { isErc20Icp } from '$eth/utils/token.utils';
import {
ckErc20HelperContractAddress,
Expand Down Expand Up @@ -165,10 +166,7 @@
name: TRACK_COUNT_CONVERT_ETH_TO_CKETH_ERROR
});

toastsError({
msg: { text: $i18n.send.error.unexpected },
err
});
toastEthereumTransactionError({ err, fallbackMsg: $i18n.send.error.unexpected });

back();
}
Expand Down
11 changes: 3 additions & 8 deletions src/frontend/src/eth/components/send/EthSendTokenWizard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
} from '$eth/stores/eth-fee.store';
import type { EthereumNetwork } from '$eth/types/network';
import type { ProgressStep } from '$eth/types/send';
import { toastEthereumTransactionError } from '$eth/utils/eth-error.utils';
import { isSupportedEthTokenId } from '$eth/utils/eth.utils';
import { capSendAmountToFee, shouldSendWithApproval } from '$eth/utils/send.utils';
import { isErc20Icp } from '$eth/utils/token.utils';
Expand Down Expand Up @@ -248,10 +249,7 @@
}
});

toastsError({
msg: { text: $i18n.send.error.unexpected },
err
});
toastEthereumTransactionError({ err, fallbackMsg: $i18n.send.error.unexpected });

onBack();
}
Expand Down Expand Up @@ -394,10 +392,7 @@
metadata: sendTrackingEventMetadata
});

toastsError({
msg: { text: $i18n.send.error.unexpected },
err
});
toastEthereumTransactionError({ err, fallbackMsg: $i18n.send.error.unexpected });

onBack();
}
Expand Down
6 changes: 5 additions & 1 deletion src/frontend/src/eth/components/swap/SwapEthWizard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import type { ProgressStep } from '$eth/types/send';
import { isTokenErcFungible } from '$eth/utils/erc-fungible.utils';
import { isTokenErc20 } from '$eth/utils/erc20.utils';
import { mapEthereumErrorMsg } from '$eth/utils/eth-error.utils';
import { isNotDefaultEthereumToken } from '$eth/utils/eth.utils';
import { isIcToken } from '$icp/validation/ic-token.validation';
import { assertCkEthMinterInfoLoaded } from '$icp-eth/services/cketh.services';
Expand Down Expand Up @@ -533,7 +534,10 @@
});
} else {
failedSwapError.set({
message: nearIntentsQuoteRejectedMessage(err) ?? $i18n.swap.error.failed_unexpectedly,
message:
nearIntentsQuoteRejectedMessage(err) ??
mapEthereumErrorMsg(err) ??
$i18n.swap.error.failed_unexpectedly,
variant: 'error'
});
}
Expand Down
100 changes: 100 additions & 0 deletions src/frontend/src/eth/utils/eth-error.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { i18n } from '$lib/stores/i18n.store';
import { toastsError, toastsErrorNoTrace } from '$lib/stores/toasts.store';
import { nonNullish } from '@dfinity/utils';
import { get } from 'svelte/store';

// How deep to follow `cause` / `error` / `info` before giving up. A provider wraps the node's own
// error two or three levels down, and no shape we have seen goes deeper than that.
const MAX_ERROR_DEPTH = 5;

// The node refuses a transaction the account cannot pay for in two different ways, both delivered
// as JSON-RPC -32000.
//
// "gas required exceeds allowance (N)" is the one that reads as a gas problem and is not: N is
// `(balance - value) / maxFeePerGas`, the gas the balance left over can still buy, so the message
// says the balance is short. It is matched as a whole phrase because an ERC-20 transfer reverts
// with "transfer amount exceeds allowance" about an approval, which is a different failure with a
// different fix and must not borrow this text.
const INSUFFICIENT_BALANCE_PATTERN = /insufficient funds|gas required exceeds allowance/i;

const ETHERS_INSUFFICIENT_FUNDS_CODE = 'INSUFFICIENT_FUNDS';

const isRecord = (value: unknown): value is Record<string, unknown> =>
nonNullish(value) && typeof value === 'object';

/**
* The messages and error codes an error carries, its own and those of every error it wraps.
*
* Ethers nests the node's answer under `error` and `info`, and re-serialises it into its own
* message on the way out, so the same failure can be described at several levels at once. Reading
* all of them means a match does not depend on which level a given provider chose to wrap.
*/
const collectErrorText = ({ err, depth = 0 }: { err: unknown; depth?: number }): string[] => {
if (typeof err === 'string') {
return [err];
}

if (depth > MAX_ERROR_DEPTH || !isRecord(err)) {
return [];
}

const { message, shortMessage, code, cause, error, info } = err;

return [
...(typeof message === 'string' ? [message] : []),
...(typeof shortMessage === 'string' ? [shortMessage] : []),
...(typeof code === 'string' ? [code] : []),
...collectErrorText({ err: cause, depth: depth + 1 }),
...collectErrorText({ err: error, depth: depth + 1 }),
...collectErrorText({ err: info, depth: depth + 1 })
];
};

const isInsufficientBalanceError = (err: unknown): boolean =>
collectErrorText({ err }).some(
(text) => text === ETHERS_INSUFFICIENT_FUNDS_CODE || INSUFFICIENT_BALANCE_PATTERN.test(text)
);

/**
* Maps an error raised while broadcasting an Ethereum or EVM transaction to a user-friendly message.
*
* Resolves i18n strings imperatively so callers don't need to pass them. Returns `undefined` when
* the error is not one we can explain, allowing callers to fall through to their own generic
* message rather than claiming a cause we have not established.
*/
export const mapEthereumErrorMsg = (err: unknown): string | undefined => {
const {
send: { error }
} = get(i18n);

if (isInsufficientBalanceError(err)) {
return error.ethereum_insufficient_funds;
}
};

/**
* Reports an error raised while broadcasting a transaction, with the node's own text attached only
* when we have no explanation of our own to offer.
*
* A recognised cause is already stated in terms the user can act on, and appending the RPC dump to
* it would bury that under the very string that makes these failures read as something they are
* not. `toastsErrorNoTrace` still writes the original error to the console, so nothing is lost for
* whoever has to diagnose it. An unexplained failure keeps the detail on screen, it being the only
* thing there is to report.
*/
export const toastEthereumTransactionError = ({
err,
fallbackMsg
}: {
err: unknown;
fallbackMsg: string;
}) => {
const msg = mapEthereumErrorMsg(err);

if (nonNullish(msg)) {
toastsErrorNoTrace({ msg: { text: msg }, err });
return;
}

toastsError({ msg: { text: fallbackMsg }, err });
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
} from '$eth/stores/eth-fee.store';
import type { EthereumNetwork } from '$eth/types/network';
import { isEthAddress } from '$eth/utils/account.utils';
import { toastEthereumTransactionError } from '$eth/utils/eth-error.utils';
import { isSupportedEthTokenId } from '$eth/utils/eth.utils';
import { isErc20Icp } from '$eth/utils/token.utils';
import { isSupportedEvmNativeTokenId } from '$evm/utils/native-token.utils';
Expand Down Expand Up @@ -259,10 +260,7 @@
metadata: sendTrackingEventMetadata
});

toastsError({
msg: { text: $i18n.send.error.unexpected },
err
});
toastEthereumTransactionError({ err, fallbackMsg: $i18n.send.error.unexpected });
}
};
</script>
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "حدث خطأ أثناء تحميل معاملات البيتكوين المعلقة. يرجى المحاولة مرة أخرى لاحقًا.",
"unexpected_utxos_fee": "حدث خطأ ما أثناء حساب رسوم المعاملة.",
"unable_to_retrieve_amount": "غير متاح (لا يمكن استرداده)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "لم تتم معالجة معاملتك بواسطة شبكة Solana وانتهت صلاحيتها، على الأرجح لأن رسوم الأولوية المقدمة لم تكن كافية. لقد قمنا بتحديثها إلى أحدث مبلغ موصى به، لذا يرجى المحاولة مرة أخرى.",
"solana_confirmation_failed": "لم نتلق تأكيدًا للمعاملة التي أنشأتها للتو. يرجى الانتظار بضع ثوانٍ ثم التحقق من قائمة معاملات التوكن الخاصة بك إذا تم إنشاء معاملتك بشكل صحيح.",
"solana_insufficient_funds": "",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "Při načítání čekajících transakcí Bitcoin došlo k chybě. Zkuste to prosím později.",
"unexpected_utxos_fee": "Při výpočtu poplatku za transakci došlo k chybě.",
"unable_to_retrieve_amount": "n/a (nelze načíst)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "Vaše transakce nebyla zpracována sítí Solana a vypršela, nejpravděpodobněji proto, že zadaný prioritní poplatek nebyl dostatečný. Aktualizovali jsme ho na nejnovější doporučenou částku, zkuste to prosím znovu.",
"solana_confirmation_failed": "Neobdrželi jsme potvrzení pro transakci, kterou jste právě vytvořili. Počkejte prosím několik sekund a poté zkontrolujte seznam transakcí vašeho tokenu, zda byla vaše transakce vytvořena správně.",
"solana_insufficient_funds": "Zůstatek vašeho tokenu není dostatečný k dokončení této transakce. Váš zůstatek se mohl od posledního zobrazení změnit.",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "Beim Laden der ausstehenden Bitcoin-Transaktionen ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
"unexpected_utxos_fee": "Beim Berechnen der Transaktionsgebühr ist ein Fehler aufgetreten.",
"unable_to_retrieve_amount": "n/v (Betrag konnte nicht abgerufen werden)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "Ihre Transaktion wurde vom Solana-Netzwerk nicht verarbeitet und ist abgelaufen, höchstwahrscheinlich weil die angegebene Prioritätsgebühr nicht ausreichend war. Wir haben sie auf den aktuell empfohlenen Betrag aktualisiert. Bitte versuchen Sie es erneut.",
"solana_confirmation_failed": "Wir haben keine Bestätigung für die soeben erstellte Transaktion erhalten. Bitte warten Sie einige Sekunden und prüfen Sie dann in der Transaktionsliste Ihres Tokens, ob Ihre Transaktion korrekt erstellt wurde.",
"solana_insufficient_funds": "Ihr Token-Guthaben reicht nicht aus, um diese Transaktion abzuschließen. Ihr Guthaben kann sich seit der letzten Anzeige geändert haben.",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "There was an error loading the pending Bitcoin transactions. Please try again later.",
"unexpected_utxos_fee": "Something went wrong while calculating transaction fee.",
"unable_to_retrieve_amount": "n/a (unable to retrieve)",
"ethereum_insufficient_funds": "Your balance is not sufficient to cover this transaction and its network fee. It may have changed since it was last displayed, so please check the amount and try again.",
"solana_transaction_expired": "Your transaction was not processed by the Solana network and expired, most likely because the provided priority fee was not sufficient. We updated it to the latest recommended amount, so please try again.",
"solana_confirmation_failed": "We did not receive a confirmation for the transaction you just created. Please wait a few seconds and then check your token’s transaction list if your transaction was created correctly.",
"solana_insufficient_funds": "Your token balance is not sufficient to complete this transaction. Your balance may have changed since it was last displayed.",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "Se produjo un error al cargar las transacciones de Bitcoin pendientes. Por favor, inténtelo de nuevo más tarde.",
"unexpected_utxos_fee": "Algo salió mal al calcular la tarifa de la transacción.",
"unable_to_retrieve_amount": "n/d (no se puede recuperar)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "Su transacción no fue procesada por la red Solana y expiró, muy probablemente porque la tarifa de prioridad proporcionada no era suficiente. La hemos actualizado al importe recomendado más reciente, por lo que por favor inténtelo de nuevo.",
"solana_confirmation_failed": "No recibimos confirmación para la transacción que acaba de crear. Por favor, espere unos segundos y luego compruebe la lista de transacciones de su token para ver si su transacción se creó correctamente.",
"solana_insufficient_funds": "El saldo de su token no es suficiente para completar esta transacción. Su saldo puede haber cambiado desde la última vez que se mostró.",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "Une erreur s'est produite lors du chargement des transactions Bitcoin en attente. Veuillez réessayer plus tard.",
"unexpected_utxos_fee": "Une erreur s'est produite lors du calcul des frais de transaction.",
"unable_to_retrieve_amount": "n/d (impossible à récupérer)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "Votre transaction n'a pas été traitée par le réseau Solana et a expiré, très probablement parce que les frais de priorité fournis n'étaient pas suffisants. Nous les avons mis à jour au montant recommandé le plus récent, veuillez donc réessayer.",
"solana_confirmation_failed": "Nous n'avons pas reçu de confirmation pour la transaction que vous venez de créer. Veuillez attendre quelques secondes, puis vérifier la liste des transactions de votre token pour voir si votre transaction a été créée correctement.",
"solana_insufficient_funds": "Le solde de votre token est insuffisant pour effectuer cette transaction. Votre solde a peut-être changé depuis son dernier affichage.",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "लंबित Bitcoin लेनदेन लोड करते समय एक त्रुटि हुई। कृपया बाद में पुनः प्रयास करें।",
"unexpected_utxos_fee": "लेनदेन शुल्क की गणना करते समय कुछ गलत हो गया।",
"unable_to_retrieve_amount": "n/a (प्राप्त करने में असमर्थ)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "आपका लेनदेन Solana नेटवर्क द्वारा संसाधित नहीं किया गया और समाप्त हो गया, सबसे अधिक संभावना है क्योंकि प्रदान की गई प्राथमिकता शुल्क पर्याप्त नहीं थी। हमने इसे नवीनतम अनुशंसित राशि पर अपडेट कर दिया है, इसलिए कृपया पुनः प्रयास करें।",
"solana_confirmation_failed": "हमें आपके द्वारा अभी बनाए गए लेनदेन की कोई पुष्टि प्राप्त नहीं हुई। कृपया कुछ सेकंड प्रतीक्षा करें और फिर अपने टोकन की लेनदेन सूची जांचें कि आपका लेनदेन सही तरीके से बनाया गया था या नहीं।",
"solana_insufficient_funds": "इस लेनदेन को पूरा करने के लिए आपके टोकन का बैलेंस पर्याप्त नहीं है। आपका बैलेंस अंतिम बार प्रदर्शित होने के बाद से बदल सकता है।",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "Si è verificato un errore durante il caricamento delle transazioni Bitcoin in sospeso. Riprova più tardi.",
"unexpected_utxos_fee": "Si è verificato un errore durante il calcolo della commissione di transazione.",
"unable_to_retrieve_amount": "n/d (impossibile recuperare)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "La tua transazione non è stata elaborata dalla rete Solana ed è scaduta, molto probabilmente perché la commissione di priorità fornita non era sufficiente. L'abbiamo aggiornata all'importo consigliato più recente, quindi riprova.",
"solana_confirmation_failed": "Non abbiamo ricevuto una conferma per la transazione che hai appena creato. Attendi qualche secondo e poi controlla la lista delle transazioni del tuo token per verificare se la tua transazione è stata creata correttamente.",
"solana_insufficient_funds": "Il saldo del tuo token non è sufficiente per completare questa transazione. Il tuo saldo potrebbe essere cambiato dall'ultima volta che è stato visualizzato.",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "保留中のBitcoinトランザクションの読み込み中にエラーが発生しました。後ほど再度お試しください。",
"unexpected_utxos_fee": "トランザクション手数料の計算中にエラーが発生しました。",
"unable_to_retrieve_amount": "n/a(取得できません)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "お客様のトランザクションはSolanaネットワークで処理されず、期限切れになりました。これは、提供された優先手数料が不十分だったためと考えられます。最新の推奨額に更新しましたので、再度お試しください。",
"solana_confirmation_failed": "作成されたトランザクションの確認を受信できませんでした。数秒お待ちいただいた後、トークンのトランザクション一覧でトランザクションが正しく作成されたかご確認ください。",
"solana_insufficient_funds": "このトランザクションを完了するためのトークン残高が不足しています。残高は最後に表示されてから変わっている可能性があります。",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/ko-KR.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "보류 중인 Bitcoin 트랜잭션을 불러오는 중에 오류가 발생했습니다. 나중에 다시 시도해 주세요.",
"unexpected_utxos_fee": "트랜잭션 수수료를 계산하는 중에 오류가 발생했습니다.",
"unable_to_retrieve_amount": "n/a (가져올 수 없음)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "귀하의 트랜잭션은 Solana 네트워크에서 처리되지 않고 만료되었습니다. 제공된 우선순위 수수료가 충분하지 않았기 때문일 가능성이 높습니다. 최신 권장 금액으로 업데이트했으니 다시 시도해 주세요.",
"solana_confirmation_failed": "방금 생성하신 트랜잭션에 대한 확인을 받지 못했습니다. 몇 초 기다린 후 토큰의 트랜잭션 목록에서 트랜잭션이 올바르게 생성되었는지 확인해 주세요.",
"solana_insufficient_funds": "이 트랜잭션을 완료하기에 토큰 잔액이 부족합니다. 잔액이 마지막으로 표시된 이후 변경되었을 수 있습니다.",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/i18n/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@
"no_pending_bitcoin_transaction": "Wystąpił błąd podczas ładowania oczekujących transakcji Bitcoin. Spróbuj ponownie później.",
"unexpected_utxos_fee": "Podczas obliczania opłaty transakcyjnej wystąpił błąd.",
"unable_to_retrieve_amount": "n/d (nie można pobrać)",
"ethereum_insufficient_funds": "",
"solana_transaction_expired": "Twoja transakcja nie została przetworzona przez sieć Solana i wygasła, najprawdopodobniej dlatego, że podana opłata priorytetowa była niewystarczająca. Zaktualizowaliśmy ją do najnowszej zalecanej kwoty, więc spróbuj ponownie.",
"solana_confirmation_failed": "Nie otrzymaliśmy potwierdzenia dla właśnie utworzonej transakcji. Poczekaj kilka sekund, a następnie sprawdź listę transakcji swojego tokena, czy Twoja transakcja została utworzona poprawnie.",
"solana_insufficient_funds": "Saldo Twojego tokena jest niewystarczające do zrealizowania tej transakcji. Twoje saldo mogło się zmienić od ostatniego wyświetlenia.",
Expand Down
Loading
Loading