Is OP_WALLET safe?
OP_WALLET sends a persistent device ID and Bitcoin wallet address to its servers on every browser start.
Each time the browser starts, the extension transmits the user's Bitcoin wallet address and a persistent 12-character random device ID (stored in chrome.storage.local) in HTTP headers to wallet.opnet.org. On BTC price fetches, a deterministic hash of the user's quantum public key is embedded in the URL path sent to api.motoswap.org, functioning as a stable wallet-linked identifier. The extension also injects a script tag into every webpage that exposes a full Bitcoin wallet API object (window.opnet) to any page script, allowing any site to detect wallet presence and prompt account access.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Wallet hash placed in Motoswap price API path
After a wallet account is configured, OP_WALLET's BTC price flow reads the quantum public key hash from preferences, puts it in a GET path to api.motoswap.org.
DA didn't capture it: it stayed at setup, rejecting an account without a key.
You open the wallet after an account has been set up.
The popup starts its BTC price loading flow when the price provider mounts.
The extension reads your wallet-derived hash and builds a Motoswap API URL with that value in the path.
The request is only built when the stored current account contains quantumPublicKeyHash.
| Field | Value | Why it matters | |
|---|---|---|---|
Wallet quantum public key hash | 0x4f3a1b2c9d0e8f76543210abcdef1234567890ab (illustrative) | This stable wallet-derived value can let the receiving service recognize the same configured wallet across price checks. | |
Chain name | bitcoin | This tells the service which blockchain context your wallet is using for the price lookup. | |
Network name | mainnet | This tells the service whether the lookup is for mainnet, testnet, signet, or another configured network. |
| Content-Type | application/json |
| X-App-Platform | web |
The popup starts the price flow and the background request embeds the wallet hash
function Fi({
children: e
}) {
const t = Ei(),
[r, n] = (0, Pr.useState)(!1),
[a, i] = (0, Pr.useState)(0),
o = (0, Pr.useCallback)(() => {
Mi || Date.now() - Li < 30 * 1e3 || (Mi = !0, n(!0), Li = Date.now(), t.getBtcPrice().then(e => {
e > 0 && i(e)
}).catch(e => {}).finally(() => {
n(!1), Mi = !1
}))
}, [t]);
(0, Pr.useEffect)(() => {
o()
}, [o]);
const s = {
isLoadingBtcPrice: r,
btcPrice: a,
refreshBtcPrice: o
};
return (0, Dr.jsx)(Di.Provider, {
value: s,
children: e
})
}async getBtcPrice() {
const e = await this.fetchPriceFromMotoswap();
if (e > 0) return e;
const t = await this.fetchPriceFromPublicAPIs();
return t > 0 ? t : this.cachedBtcPrice
}async fetchPriceFromMotoswap() {
try {
const e = preference_default.getChainType(),
t = preference_default.getCurrentAccount();
if (!t?.quantumPublicKeyHash) return 0;
const {
chain: n,
network: r
} = this.getChainAndNetwork(e), i = `https://api.motoswap.org/api/v1/${n}/${r}/${t.quantumPublicKeyHash.startsWith("0x")?t.quantumPublicKeyHash:`0x${t.quantumPublicKeyHash}`}/sync`, s = await this.fetchWithTimeout(i, {
method: "GET",
headers: {
"Content-Type": "application/json",
"X-App-Platform": "web"
}
});
if (!s.ok) return 0;
const o = (await s.json()).exchangeRates?.rates?.usd?.value;
return "number" == typeof o && o > 0 ? (this.updateCachedPrice(o), o) : 0
} catch {
return 0
}
}Where it sends data
Destinations our analysis observed OP_WALLET contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- api.motoswap.org
OP_WALLET sends data to api.motoswap.org. No other extension we have analysed sends data here.
- wallet.opnet.org
OP_WALLET sends data to wallet.opnet.org. No other extension we have analysed sends data here.