[BUG] toNexusAccount fails when the user has no wallet extensions installed
- Dominant language
- TypeScript
- Stars
- 8
- Forks
- 12
- Avg merge
- 2h 15m
- Merged PRs (30d)
- 1
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Package Version
1.2.4
### Current Behavior
The library expects an Ethereum wallet extension installed, so if a user has no wallet extensions installed (`window.ethereum` === `undefined`), for example by connecting using a 3rd party connector via email or their web2 account, `toNexusAccount` fails with the following error:
```
TypeError: Cannot read properties of undefined (reading 'request')
at Object.transport (_esm-BSwfxQyV.js?v=4ff14d18:5862:21)
at createClient (parseSignature-BmMoHAM7.js?v=4ff14d18:25:48)
at createWalletClient (_esm-BSwfxQyV.js?v=4ff14d18:5816:9)
at toWalletClient (@biconomy_abstractjs.js?v=4ff14d18:70507:9)
at toNexusAccount (@biconomy_abstractjs.js?v=4ff14d18:70643:23)
```
```js
const walletClient = toWalletClient({
unresolvedSigner: _signer,
resolvedSigner: signer,
chain,
transport: transportConfig
});
```
```js
//#region node_modules/.pnpm/@biconomy+abstractjs@1.2.4_@metamask+delegation-toolkit@0.11.0_viem@2.52.2_bufferutil@4_2a944230c8f4986aa78e4c29ea8e997a/node_modules/@biconomy/abstractjs/dist/_esm/account/utils/toWalletClient.js
var toWalletClient = ({ unresolvedSigner, resolvedSigner, chain, transport }) => {
return createWalletClient(unresolvedSigner?.transport?.key === "custom" ? {
account: resolvedSigner.address,
chain,
transport: custom(window?.ethereum)
} : {
account: resolvedSigner,
chain,
transport
}).extend(publicActions);
};
//#endregion
```
```js
//#region node_modules/.pnpm/viem@2.52.2_bufferutil@4.1.0_typescript@6.0.3_utf-8-validate@6.0.6_zod@4.4.3/node_modules/viem/_esm/clients/createWalletClient.js
function createWalletClient(parameters) {
const { key = "wallet", name = "Wallet Client", transport } = parameters;
return createClient({
...parameters,
key,
name,
transport,
type: "walletClient"
}).extend(walletActions);
}
//#endregion
```
```js
//#region node_modules/.pnpm/viem@2.52.2_bufferutil@4.1.0_typescript@6.0.3_utf-8-validate@6.0.6_zod@4.4.3/node_modules/viem/_esm/clients/transports/custom.js
/**
* @description Creates a custom transport given an EIP-1193 compliant `request` attribute.
*/
function custom(provider, config = {}) {
const { key = "custom", methods, name = "Custom Provider", retryDelay } = config;
return ({ retryCount: defaultRetryCount }) => createTransport({
key,
methods,
name,
request: provider.request.bind(provider),
retryCount: config.retryCount ?? defaultRetryCount,
retryDelay,
type: "custom"
});
}
//#endregion
```
### Expected Behavior
_No response_
### Steps To Reproduce
Run a working app on incognito (no Ethereum wallet extensions enabled)
### Package.json (or lockfile) content
```json
{
"name": "xxx",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": { "xxx": "xxx" },
"dependencies": {
"@biconomy/abstractjs": "^1.2.4",
"@dynamic-labs/ethereum": "^4.88.6",
"@dynamic-labs/sdk-react-core": "^4.88.6",
"@dynamic-labs/wagmi-connector": "^4.88.6",
"@tailwindcss/vite": "^4.3.1",
"@tanstack/react-query": "^5.101.0",
"alchemy-sdk": "^3.6.5",
"daisyui": "^5.5.23",
"firebase": "^12.14.0",
"permissionless": "^0.3.6",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-icons": "^5.6.0",
"react-router": "^7.17.0",
"react-toastify": "^11.1.0",
"tailwindcss": "^4.3.1",
"viem": "^2.52.2",
"wagmi": "^3.6.16"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@types/node": "^24.13.2",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.2",
"eslint": "^10.5.0",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.6.0",
"typescript": "~6.0.3",
"typescript-eslint": "^8.61.0",
"vite": "^8.0.16"
}
}
```
### Link to Minimal Reproducible Example (StackBlitz, CodeSandbox, GitHub repo etc.)
_No response_
### Anything else?
My workaround now is by doing:
```ts
if (!window.ethereum) {
window.ethereum = {
async request(_: any): Promise {},
} as any;
}
toNexusAccount({
chainConfiguration: {
chain,
transport: http(import.meta.env.VITE_BASE_SEPOLIA_RPC_URL),
version: getMEEVersion(MEEVersion.V2_3_0),
versionCheck: false,
},
...
});
```
This works, but it would be great if abstractjs doesn't assume a wallet client / handle the case for `transport: custom(window?.ethereum)` when `window?.ethereum` is `undefined`
Thanks
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at the toWalletClient call shown in the report and reproduce with no window.ethereum, using the supplied transport. Trace how toNexusAccount selects custom(window?.ethereum), then add coverage for the no-extension path and verify that toNexusAccount completes without reading request from undefined.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- blockchain
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100