The browser extension and window.varnir
Why this matters
The extension keeps a user's Varnir keys in the browser's wallet, not in a web page. A site asks it to sign; the extension shows the user a plain summary in its own window, and nothing is signed until they approve. That is the model people already know from Ethereum wallets, so the risk of a compromised or spoofed page signing something unseen is lower than with a wallet that lives inside the page.
The extension (apps/wallet-extension, Chrome Manifest V3, Chrome 116 or
later) is built, and the scanner uses it when it is installed. It is not yet
in the Chrome Web Store; today it is loaded unpacked from a build. The full
reference is the extension's
README;
this page is a summary of it.
Who can use the provider
Only Varnir's own sites. The provider is injected on
https://scanner.varnir.site and https://playground.varnir.site, top frame
only (a development build adds http://localhost and http://127.0.0.1 on any
port). It is not injected anywhere else, and the extension refuses a request
from any other origin with 4100. A third-party site cannot ask it to sign.
To build on Varnir from your own site or server, use the SDK instead. This page is for people working on Varnir's own web apps, and for anyone who wants to understand what the extension does.
What the user sees
- The wallet in the toolbar. The popup is the scanner's wallet dock: the
same components, from the shared
packages/wallet-uipackage, with data kept inchrome.storage.local. - Approval in the wallet's own window. Every request that signs something opens an extension window with a plain summary. A send shows the amount and token, from and to (with the contact's name), network, the note, the payout speed and its credits, the network fee for a native on-chain send (Varnir fronts a token's gas), "first payment to this recipient" when it applies, and a warning for a deliberate repeat. A send is held to confirm. A request the extension has no summary for is refused.
- Keys stay in the extension. The vault lives in the extension's service worker. Web pages get signatures and results, never a key.
- Move to extension. A wallet saved on the scanner can be moved into the extension. The user enters their site PIN, pattern or password; the site copy is removed only for the accounts the extension took.
The provider
window.varnir follows
EIP-1193, the Ethereum provider
standard, so the shape will be familiar:
function onProvider(callback) {
if (window.varnir?.isVarnir) return callback(window.varnir);
window.addEventListener('varnir#initialized', () => callback(window.varnir), {once: true});
}
onProvider(async (varnir) => {
const [identity] = await varnir.request({method: 'varnir_requestAccounts'});
const result = await varnir.request({
method: 'varnir_send',
params: {network: 'niles', to: 'TSC9KBw...', amount: '1.5', speed: 'economy'},
});
// result: { umid, settledOn, proposal?, hold?, speed?, speedRecorded? }
});
It also answers an EIP-6963-shaped
handshake under Varnir's own event names (varnir:requestProvider /
varnir:announceProvider), so an Ethereum wallet picker never offers it as an
EVM wallet.
| Standard | Where it shows up |
|---|---|
| EIP-1193 | request({ method, params }), on / removeListener, error objects with code |
| EIP-1474 | -32602 invalid params, -32603 internal error |
| EIP-1102 | Connect first (varnir_requestAccounts), then read accounts |
| MetaMask | the varnir#initialized event, and approval in a separate notification window |
Method groups
The README has every method with its params and result. In outline:
| Group | Methods | Approval window |
|---|---|---|
| Accounts | varnir_requestAccounts, varnir_accounts, varnir_getLockState, varnir_getEnvironment, varnir_getPublicKey | Only the first connect |
| Sending and signing ledger actions | varnir_send, key, invoice, rename, webhook, order, held-transfer, recovery and plan methods | Always |
| Signed API requests | varnir_signApiRequest | Writes always; reads (GET routes) are signed without a window once the site is connected and the wallet is unlocked |
| Contacts | varnir_contacts_list, _add, _update, _remove, _replace | No (nothing is signed) |
| Move to extension | varnir_importWallet | Yes, with the site's lock |
varnir_send takes
{ network: "niles" | "sep" | "tbnb", to, amount, token?, symbol?, ref?, speed?, repeat?, settlement? }.
The amount is a human decimal, scaled by the on-ledger token registry's
decimals for a token; a decimals field, or any field not listed, is
-32602, and a token the registry doesn't know is refused before any window
opens. It is carried out as the SDK's send(), so a Varnir address settles
on the ledger and anything else is an L1 withdrawal.
Errors
| Code | Meaning |
|---|---|
4001 | The user rejected the request, or closed the window |
4100 | Not authorised: not a Varnir origin, the site isn't connected, the connected account was removed, or a contacts call or signed read while the wallet is locked |
4200 | Unsupported method, or an API route the extension won't sign |
4900 | Disconnected: the extension was reloaded or removed, or the user disconnected the site |
4901 | The connection to the extension dropped before an answer; safe to retry |
-32602 | Invalid params, checked before any window opens |
-32603 | The approved request failed. When the ledger names the reason, data.varnirCode carries the SDK's error code, for example REPEAT_PAYMENT with the earlier payment's umid and time |
Events
accountsChanged, lockChanged, contactsChanged, environmentChanged and
disconnect. There is no chainChanged: there is no chain to switch.
Not done yet
- The Chrome Web Store release.
- Biometric unlock in the extension (PIN, pattern and password work).
- Market orders through the extension (Make, Take and Cancel work).
- A Firefox build.