43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
/**
|
|
* MetaMask / EIP-1193 wallet error helpers.
|
|
*
|
|
* Previously the codebase detected user rejections by string-matching the
|
|
* error message for "reject" or "denied". That breaks when MetaMask's UI
|
|
* language is set to anything other than English (the message is translated
|
|
* but our match string isn't). The reliable signal is the EIP-1193 error
|
|
* code: 4001 = "User rejected the request".
|
|
*
|
|
* Wagmi sometimes wraps the underlying provider error inside `.cause`, so we
|
|
* walk that chain too.
|
|
*/
|
|
|
|
interface WithCode {
|
|
code?: number | string
|
|
cause?: unknown
|
|
}
|
|
|
|
export function isUserRejection(err: unknown): boolean {
|
|
// Walk a small depth of .cause chains since wagmi/viem wrap provider errors
|
|
let cur: unknown = err
|
|
for (let i = 0; i < 4 && cur; i++) {
|
|
const c = (cur as WithCode)?.code
|
|
if (c === 4001 || c === 'ACTION_REJECTED' || c === 'USER_REJECTED') return true
|
|
cur = (cur as WithCode)?.cause
|
|
}
|
|
// Last-resort string fallback for providers that don't expose a code field.
|
|
// Kept narrow — "reject" + "denied" + a couple of locale variants we've
|
|
// actually seen from MetaMask zh-CN ("拒绝") and Rabby ("rejected by user").
|
|
const m = err instanceof Error ? err.message : ''
|
|
return /reject|denied|cancell|拒绝|已取消/i.test(m)
|
|
}
|
|
|
|
/**
|
|
* Convenience: return either a friendly cancellation label or a truncated
|
|
* version of the real error message — never raw user-facing crash text.
|
|
*/
|
|
export function walletErrorLabel(err: unknown, cancelledLabel = 'Cancelled', maxLen = 110): string {
|
|
if (isUserRejection(err)) return cancelledLabel
|
|
const m = err instanceof Error ? err.message : String(err ?? '')
|
|
return m.slice(0, maxLen) || 'unknown error'
|
|
}
|