rainbow-me / browser-extension Goto Github PK
View Code? Open in Web Editor NEWAn Ethereum wallet built for speed 🌈
Home Page: https://rainbow.me/
License: GNU General Public License v3.0
An Ethereum wallet built for speed 🌈
Home Page: https://rainbow.me/
License: GNU General Public License v3.0
In general I find that Rainbow has way better UX than notable competitors. However I've noticed a few areas where it has significant room for improvement. One is renaming wallets, which I find incredibly painful. Currently the process is:
w
to get a list of all walletsThis requires far too many clicks. Imagine you want to rename 5 wallets. This would require 25 clicks plus 5 scrollings on top of typing the 5 names!
This process is even worse when importing a new wallet by specifying a private key, because you can't specify a name during the import, requiring 3 mouse clicks to initiate the import, plus the 5 extra for the rename. Worse, the new wallet gets buried at the end of the list of wallets in step 2 above, and you can't search for it unless you already know the address, because it doesn't have a name yet. So you have to scroll all the way down the list to find it. That means that on top of the unavoidable pasting of the private key and typing of the wallet names, importing and naming 5 new wallets would require something like 40 clicks plus a lot of scrolling!
Fortunately, all of these problems can be fixed very easily. All of the following suggestions can be implemented independently from each other, and all of them would considerably improve the UX:
Steps to reproduce the issue:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>accountsChanged Test</title>
</head>
<body>
<script>
const wallets = [];
window.addEventListener('eip6963:announceProvider', e => wallets.push(e.detail));
window.dispatchEvent(new Event('eip6963:requestProvider'));
for (const wallet of wallets) {
wallet.provider.addListener?.('accountsChanged', console.log) ?? wallet.provider.on('accountsChanged', console.log);
}
</script>
</body>
</html>
Expected result: two accountsChanged
events are emitted. One upon connection and one upon disconnection. The DevTools console log should look like this:
> ['0xaaa..aaa']
> []
Actual result: only one accountsChanged
event is emitted, upon connection. The DevTools console log looks like this:
> ['0xaaa..aaa']
Here's the relevant part of EIP-1193:
accountsChanged
If the accounts available to the Provider change, the Provider MUST emit the event named
accountsChanged
with valueaccounts: string[]
, containing the account addresses per theeth_accounts
Ethereum RPC method.The “accounts available to the Provider” change when the return value of
eth_accounts
changes.
Since the return value of eth_accounts
changes when the wallet disconnects (from an array with 1 address to an empty array), the accountsChanged
event must be emitted.
I performed the above steps with MetaMask and Brave Wallet, and they both emit 2 events as expected.
Using fresh Brave browser profile with only rainbow wallet installed.
Have transferred all my wallets over from metamask.
Disabled brave wallets.
Rainbow will never connect to any website, including opensea, uniswap, etc.
When selecting what wallet to connect, on selecting "metamask" I will get redirected to download metamask rather than rainbow wallet opening. Likewise when I select "browser wallet".
Is there a way to force Rainbow wallet to open and connect?
Using wagmi 2.6.x
import { getConnectorClient } from '@wagmi/core'
const client = await getConnectorClient({ ... }, {
account: '0x...',
chainId: 314159,
connector: ...,
})
await client.request({
method: 'wallet_watchAsset',
params: {
type: 'ERC20',
options: {
address: '0xaC26a4Ab9cF2A8c5DBaB6fb4351ec0F4b07356c4',
symbol: 'WFIL',
decimals: 18,
},
},
})
When sending the wallet_watchAsset
request, a window pops up to approve adding the token:
However, when clicking Approve, an error is thrown: User rejected the request.
When I try to add addresses from Trezor T it sees only one. I use different path it finds it seems to be ok, but when I'm adding the second address it is not there and still only the first address is visible in the wallet. Same problem is with signing transaction, it fails despite I confirm on wallet.
Also claiming points with Trezor T is not working at all, with the first address ofc, I can't add more than just the first address.
`
LavaMoat generating policy from entry "/Users/henry/Desktop/Backend/browser-extension/scripts/webpack.js"...
645 | }
646 | if (!loaded) {
647 | require(request);
| ^^^^^^^^^^^^^^^^ dynamic require
648 | }
649 |
650 | loadedRequests.add(request);
lavamoat - unable to resolve "pnpapi" from "/Users/henry/Desktop/Backend/browser-extension/node_modules/webpack/node_modules/enhanced-resolve/lib/ResolverFactory.js"
⚠️ Potentially Incompatible code detected in package "webpack" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/webpack/lib/ProgressPlugin.js":
410 | currentLoader = loader.loader;
411 | update();
412 | require(loader.loader);
| ^^^^^^^^^^^^^^^^^^^^^^ dynamic require
413 | }
414 | }
415 | if (currentLoader) {
⚠️ Potentially Incompatible code detected in package "webpack>loader-runner" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/loader-runner/lib/loadLoader.js":
17 | } else {
18 | try {
19 | var module = require(loader.path);
| ^^^^^^^^^^^^^^^^^^^^ dynamic require
20 | } catch(e) {
21 | // it is possible for node to choke on a require if the FD descriptor
22 | // limit has been reached. give it a chance to recover.
⚠️ Potentially Incompatible code detected in package "webpack>browserslist" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/browserslist/node.js":
174 | checkExtend(name)
175 | }
176 | var queries = require(require.resolve(name, { paths: ['.', ctx.path] }))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dynamic require
177 | if (queries) {
178 | if (Array.isArray(queries)) {
179 | return queries
195 | checkExtend(name)
196 | }
197 | var stats = require(require.resolve(
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
198 | path.join(name, 'browserslist-stats.json'),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
199 | { paths: ['.'] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
200 | ))
| ^^^^^^ dynamic require
201 | return normalizeStats(data, stats)
202 | },
203 |
246 | var compressed
247 | try {
248 | compressed = require('caniuse-lite/data/regions/' + code + '.js')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dynamic require
249 | } catch (e) {
250 | throw new BrowserslistError("Unknown region name " + code + ".")
251 | }
266 | var compressed
267 | try {
268 | compressed = require('caniuse-lite/data/features/' + name + '.js')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dynamic require
269 | } catch (e) {
270 | throw new BrowserslistError("Unknown feature name " + name + ".")
271 | }
lavamoat - unable to resolve "uglify-js" from "/Users/henry/Desktop/Backend/browser-extension/node_modules/terser-webpack-plugin/dist/utils.js"
lavamoat - unable to resolve "uglify-js/package.json" from "/Users/henry/Desktop/Backend/browser-extension/node_modules/terser-webpack-plugin/dist/utils.js"
lavamoat - unable to resolve "@swc/core" from "/Users/henry/Desktop/Backend/browser-extension/node_modules/terser-webpack-plugin/dist/utils.js"
lavamoat - unable to resolve "@swc/core/package.json" from "/Users/henry/Desktop/Backend/browser-extension/node_modules/terser-webpack-plugin/dist/utils.js"
lavamoat - unable to resolve "pnpapi" from "/Users/henry/Desktop/Backend/browser-extension/node_modules/esbuild/lib/main.js"
⚠️ Potentially Incompatible code detected in package "webpack>terser-webpack-plugin>jest-worker" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/terser-webpack-plugin/node_modules/jest-worker/build/index.js":
66 |
67 | if (!exposedMethods) {
68 | const module = require(workerPath);
| ^^^^^^^^^^^^^^^^^^^ dynamic require
69 |
70 | exposedMethods = Object.keys(module).filter(
71 | // @ts-expect-error: no index
⚠️ Potentially Incompatible code detected in package "@vanilla-extract/vite-plugin>@vanilla-extract/integration" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/@vanilla-extract/integration/dist/vanilla-extract-integration.cjs.prod.js":
272 | const {
273 | name
274 | } = require(packageJsonPath);
| ^^^^^^^^^^^^^^^^^^^^^^^^ dynamic require
275 |
276 | return {
277 | name,
⚠️ Potentially Incompatible code detected in package "@vanilla-extract/vite-plugin>@vanilla-extract/integration" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/@vanilla-extract/integration/dist/vanilla-extract-integration.cjs.dev.js":
272 | const {
273 | name
274 | } = require(packageJsonPath);
| ^^^^^^^^^^^^^^^^^^^^^^^^ dynamic require
275 |
276 | return {
277 | name,
lavamoat - unable to resolve "babel-register" from "/Users/henry/Desktop/Backend/browser-extension/node_modules/dotenv-webpack/index.js"
lavamoat - unable to resolve "./src" from "/Users/henry/Desktop/Backend/browser-extension/node_modules/dotenv-webpack/index.js"
⚠️ Potentially Incompatible code detected in package "ts-loader" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/ts-loader/dist/instances.js":
225 | else if (typeof customerTransformers === 'string') {
226 | try {
227 | customerTransformers = require(customerTransformers);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dynamic require
228 | }
229 | catch (err) {
230 | throw new Error(Failed to load customTransformers from "${instance.loaderOptions.getCustomTransformers}": ${err instanceof Error ? err.message : 'unknown error'});
⚠️ Potentially Incompatible code detected in package "ts-loader" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/ts-loader/dist/compilerSetup.js":
9 | let compilerCompatible = false;
10 | try {
11 | compiler = require(loaderOptions.compiler);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dynamic require
12 | }
13 | catch (e) {
14 | errorMessage =
⚠️ Potentially Incompatible code detected in package "typescript" file "/Users/henry/Desktop/Backend/browser-extension/node_modules/typescript/lib/typescript.js":
3096 | try {
3097 | const etwModulePath = process.env.TS_ETW_MODULE_PATH ?? "./node_modules/@microsoft/typescript-etw";
3098 | etwModule = require(etwModulePath);
| ^^^^^^^^^^^^^^^^^^^^^^ dynamic require
3099 | } catch (e) {
3100 | etwModule = void 0;
3101 | }
6267 | try {
6268 | const modulePath = resolveJSModule(moduleName, baseDir, nodeSystem);
6269 | return { module: require(modulePath), modulePath, error: void 0 };
| ^^^^^^^^^^^^^^^^^^^ dynamic require
6270 | } catch (error2) {
6271 | return { module: void 0, modulePath: void 0, error: error2 };
6272 | }
LavaMoat wrote policy to "/Users/henry/Desktop/Backend/browser-extension/lavamoat/build-webpack/policy.json"
`
I got this error when run "yarn setup"
I have seen wallet plugins that support bybit wallet, but the network does not support mantle, mantle is a second layer with a large number of users, looking forward to adding it.
network Name: Mantle
rpc url: https://mantle.public-rpc.com/
chain ID: 5000
Currency symbol: MNT
Blocks the browser: https://explorer.mantle.xyz/
hehe i’m first
On most DAPPs, the rainbow browser-extension can connect using the metamask option (e.g.: https://app.aave.com/), however, it seems that on DAPPs that are using rainbowkit, unless they enable "rainbow" as a wallet, the browser extension cannot connect using the "metamask" option (it just shows a link to download the extension) (e.g: https://app.stcelo.xyz/stake).
Since you develop both softwares, is there a way to make one of the other allow the extension to connect as if it was metamask?
Thanks!
I appreciate the minimalism in the transaction view (where a transaction is displayed to the user for them to sign), but the lack of features there does make some transactions difficult or outright impossible. These could be hidden away on a dropdown, hotkey or gear icon somewhere, but they should be there.
I'll list a few here but if others have more suggestions I'm happy to add them to the list:
Currently I do not know if a dapp prompted me to approve an exact amount of tokens, infinite amount or a 0 amount (to revoke approval). The function name is displayed, but that's it. Some of the blame here should be shifted to bad dapp design, but still - we should be able to see that, with bonus points for being able to edit the amount :)
It should also be possible to display what token is being approved, for what address, and if using something like Permit2 with an expiry, when it is valid until.
Estimating gas limits is hard. I know. In general I'd be OK with the wallet largely overestimating this to avoid running into "out of gas" reverts, but ultimately we need a way to set this ourselves. For example, this TX ran out of gas with ~170k estimated and I had to resubmit it with a higher gas limit to get it through (had to use another wallet in order to do this). Went through here with ~198k.
Similarly to the previous point, we should be able to see what the value is currently set at, and edit it if necessary. Most users should not care about this or need this, but the feature should be hidden away somewhere for those that do.
conflicts with other browser extensions
I'm testing on a local Dapp on latest Chrome on MacOS. Metamask and Coinbase extensions work fine. Rainbow is also able to connect to the page and sign a message. But for every other action, like minting a token, it fails. I see this error spamming my console:
inpage.js:1 Uncaught (in promise) TypeError: Error in invocation of runtime.sendMessage(optional string extensionId, any message, optional object options, optional function callback): chrome.runtime.sendMessage() called from a webpage must specify an Extension ID (string) for its first argument.
And for an example mint function, I get this error:
Error: missing revert data in call exception; Transaction reverted without a reason string [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (data="0x", transaction={"from":"REMOVED_FOR_GITHUB","to":"REMOVED_FOR_GITHUB","data":"REMOVED_FOR_GITHUB","accessList":null}, error={}, code=CALL_EXCEPTION, version=providers/5.7.2) at _Logger.makeError (index.ts:269:28) at _Logger.throwError (index.ts:281:20) at checkError (json-rpc-provider.ts:66:16) at Web3Provider.<anonymous> (json-rpc-provider.ts:642:20) at Generator.throw (<anonymous>) at rejected (json-rpc-provider.ts:20:1)
The exact same action and calldata works fine on metamask and coinbase.
Hey there! I've been really enjoying the browser extension, but I wanted to highlight that it doesn't recognize the Ledger Stax in the WebHID connection dialog. I'm pretty sure it's simply a matter of adding the Stax's USB identifier to the code where you open up the WebHID connection, and it'll just work from there.
2.0.0
2.5.6
I already add a custom chain to getDefaultConfig
switchChain
from useSwitchChain
wagmi for Rainbow wallet to switch to this chain, error occured like this:When I used switchChain
for other wallets like MetaMask, it worked, but rainbow didn't
wallet_addEthereumChain
to add this chain to Rainbow wallet, though I approved the addition of this chain, the error occured. I checked Rainbow wallet networks, this custom chain is already added but error showed:When I used switchChain
from useSwitchChain
wagmi for Rainbow wallet to switch to a custom chain, it should add the custom chain to RainBow wallet and switch to it
If I use wallet_addEthereumChain
, Rainbow wallet should add the chain and not show any error
No response
No response
No response
When using the send feature, the transaction appears to hang within the extension and never get submitted. Specifically in this case, I was sending ETH on mainnet.
See the below image:
I tried sending funds to both internal addresses within the app as well as external addresses. Regardless, the transaction hangs indefinitely.
I am using Ubuntu/Chrome. The rainbow plugin shows it is on v1.2.56
Note: This issue is present on Windows/Chrome as well.
Every time I open up or try to do any action using the browser extension my CPUs go crazy.
I can actually hear them spin up. % usage jumps to ~!5%. The extension itself becomes really slow.
When I initially open it, it's basically unusable, so I wait 2-3 seconds to "cool down" to around 7-8% CPU usage, before clicking or performing any next action.
I've had this issue since the launch of the extension (Oct '23) and disabled it immediately again after installing.
There's some DM history on twitter (@wslyvh).
I recently formatted and did a clean install of OS + Browser + extensions, so wanted to give it another try but still experiencing the same issues.
Laptop: System76 Lemur Pro (11th gen, i7, 40GB ram)
OS: Pop_OS 22.04
Firefox version: 122.0
Rainbow extension version: 1.3.62
Only 1 wallet address is added: wslyvh.eth
1.1.3
1.4.5
TypeError: Error in invocation of runtime.sendMessage(optional string extensionId, any message, optional object options, optional function callback): chrome.runtime.sendMessage() called from a webpage must specify an Extension ID (string) for its first argument.
No error lol
"dependencies": {
"@headlessui/react": "^1.7.17",
"@heroicons/react": "^2.0.18",
"@rainbow-me/rainbowkit": "^1.1.3",
"@rainbow-me/rainbowkit-siwe-next-auth": "^0.3.2",
"alchemy-sdk": "^2.10.1",
"ethers": "^5.7.2",
"mongoose": "^8.0.0",
"next": "^14.0.1",
"react": "^18",
"react-dom": "^18",
"react-hot-toast": "^2.4.1",
"siwe": "^2.1.4",
"swr": "^2.2.4",
"viem": "^1.18.0",
"wagmi": "^1.4.5"
},
clicking connect just throws error
No response
No response
When a contract interaction is expected to revert, I would expect the primary action to be disabled and a proper error message (from revert data) to be displayed (for this case "Token ID is taken"):
Can repro by performing mint(69)
on https://etherscan.io/address/0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2#writeContract.
Run touch .env
, head to the browser-extension-env
repository, and copy + paste the variables into your .env
Getting a few weird issues when using Rainbow + remix.ethereum.org + OP Sepolia
I can connect fine but for some reason Remix doesn't detect any accounts at first
I have to go to the extension, click "switch wallet", then click again on the wallet that is already connected.
I'm then able to see the wallet but Remix thinks the wallet has no balance (it does).
When deploying a contract I get a failed simulation that appears to be trying to simulate against Ethereum mainnet even though the transaction is against OP Sepolia.
Lastly when I deploy a contract remix either hangs or crashes.
What was the reason for disabling hardware wallet support on Firefox? Is it possible to bring that back anytime soon? I'd prefer firefox over chrome for privacy reasons.
Auditing rainbow is complicated, because it's too big. Size can easily be reduced by removing and replacing dependencies.
Probably a deep dive into all deps would reveal hundreds of kilobytes of unused code.
BIP44 e.g. : m / purpose' / coin_type' / account' / change / address_index
Checking which network is currently connected is one of the most commonly needed actions in a wallet, so it should be possible to do this immediately and easily by looking at the main page of the extension popup. There is a miniscule network icon within the icon in the top left corner, but this is far too small for it to be easy to differentiate, so currently you have to press n
or click that icon.
Ideally the network name would be visible on the main popup, as well as the icon.
Apparently, wallet_switchEthereumChain
doesn't work with networks added through wallet_addEthereumChain
is this intentional?
window.rainbow.request({
"method": "wallet_addEthereumChain",
"params": [
{
"chainId": "0x2329",
"chainName": "Evmos",
"nativeCurrency": {
"decimals": 18,
"name": "Evmos",
"symbol": "EVMOS"
},
"rpcUrls": [
"http://localhost:3000/api/eth-json-rpc/evmos"
],
"blockExplorerUrls": [
"https://escan.live"
]
}
]
})
(this works, this adds the network to my wallet, it doesn't auto switch to it after that though as is the behavior in other wallets)
2. Try to switch to the network
window.rainbow.request({
"method": "wallet_switchEthereumChain",
"params": [
{
"chainId": "0x2329",
}
]
})
I get the following error
{
"name": "Invalid Request",
"message": "Chain Id not supported",
"code": -32600
}
digging the code a little bit it seems that only what's in this list here is supported, is that correct?
wallet_addEthereumChain
seems to check for a featureFlags.custom_rpc
flag, but wallet_switchEthereumChain
right below it doesnt
https://github.com/rainbow-me/provider/blob/586aa46965b41173bd071d7ca2bdccf70ef10b0c/src/handleProviderRequest.ts#L239
This wallet should have an anti-phishing detect like metamask
Hi! Loving the browser extension. I have used it to onboard several new users to crypto! While taking a fresh look at Rainbow, I put together several suggestions for improvements that I think could be beneficial:
Improvements:
2.0.0
2.5.6
Normal icon of some site
appIcon
using getDefaultConfig
I use real domain, icon URL and project ID
export const config = getDefaultConfig({
...
appUrl: 'https://real-domain.com,
appIcon: 'https://real-domain.com/icon.png',
projectId: '01001001110100100010010',
...
})
No response
I did not find any information regarding the icon even in the open repository of rainbowkit.com
I'm using json rpc middlewares with https://github.com/MetaMask/eth-json-rpc-middleware and it seems working with the most of injectable wallets. And recently I've discovered it doesn't work with Rainbow's so I dived deeper and discovered that your sendAsync method doesn't accept second argument - callback and instead returns just promise.
Example of problem:
window.rainbow.sendAsync(jsonRpcRequest, (err, jsonRpcResponse) => {
// it'll never happen, callback is never called
})
As a user I expect token TX to display the receiving address, not the token contract
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.