Blog

DeFi Wallet Testing With Browser Agents

DeFi wallet testing follows the app, wallet extension, chain, and approval boundary with screenshots, provider state, safe fixtures, and a reviewable trace.

Drew Stone
browser-agentdefiwallet-testing
An editorial still life about an agent operating a web browser

The swap page says “Connected,” but the wallet prompt shows a different account on a different chain. The test clicks through the page, reports success, and never inspects the prompt where the user would have noticed the problem.

DeFi wallet testing has to follow four states at once: the application, the wallet extension, the chain connection, and the user’s approval. DeFi means finance applications that use blockchain accounts and smart contracts, or programs deployed on a blockchain, for actions such as swaps, lending, borrowing, and liquidity provision. A token allowance is a limit on how much a contract may spend from an account. A wallet extension manages keys and displays the approval prompts. The browser page can request work from the wallet, but it does not own the key or the final approval.

Tangle Browser Agent opens pages, observes Document Object Model state, and executes bounded browser actions toward a stated goal. After installing the public driver, run bad --help to inspect the Browser Agent commands available from a terminal. The public driver repository documents wallet and DeFi testing support alongside screenshots, page observations, and browser actions. The DOM, or Document Object Model, is the page’s structured tree of elements and attributes. Capture page, wallet, provider, and chain evidence in one timeline. For the narrower MetaMask fixture and release workflow, read MetaMask Automated Testing For Wallet Flows.

Track application, wallet, provider, and chain state

A form test usually reads and submits Document Object Model state from one page. A DeFi flow crosses several state owners whose values can disagree. RPC, or remote procedure call, is the request-and-response interface used to ask a wallet provider or chain client for account, chain, balance, and transaction information.

StateWhat it controlsExample failure
applicationselected asset, amount, route, and displayed statusThe page keeps an old account after the wallet changes.
wallet extensionaccount access, network prompts, signatures, and transaction confirmationThe prompt names the wrong chain or spender.
provider and RPC clientrequests between the page, wallet, and chain clientThe request is rejected or points at a disconnected chain.
chain and contractbalances, allowances, transaction execution, and confirmationThe transaction reverts or the UI reports success too early.

A dapp is a web application that calls smart contracts through wallet and provider interfaces from a web page. A spender is the contract allowed to use tokens under that allowance.

The test should name which state it is checking at each step. A sample instruction such as “Swap 10 test tokens” is incomplete if the test does not record the account, chain, token, route, approval, transaction state, and final balance or status.

Work through a safe swap example

Use a resettable account funded only on a local chain or named test network. Start with a small read-only quote. Stop at the wallet prompt before any signature unless the case explicitly authorizes a test-wallet transaction.

Goal: connect the disposable wallet, switch to the configured test chain,
enter a small token swap, verify the quoted route and approval details,
capture the wallet prompt, and stop before signing.
Starting state: fresh browser profile, known account, funded test balance,
known token contracts, and reset application data.
Forbidden actions: production-network (mainnet) signing, real-value transfer, unknown approval,
or accepting a prompt whose account or chain does not match the case.

Record the connect, chain, quote, prompt, rejection, and final-state checkpoints:

  1. The application detects the wallet and shows the selected account.
  2. The provider reports the expected chain identifier.
  3. The quote shows the requested input token, output token, amount, and route.
  4. The wallet prompt shows the account, chain, contract, and requested action.
  5. The application remains truthful when the user rejects the prompt.
  6. The run stops or continues only according to the explicit test policy.

The test should capture the prompt before approval. Capture the quote, route, amount, and requested action beside the page screenshot. Require the wallet screenshot to show the account, chain, spender, asset, amount, and action presented for authorization. The post-rejection screenshot explains whether the app recovered.

What to save for each checkpoint

A trace is the ordered record of an agent run. For wallet testing, it needs page state and wallet state in the same timeline.

CheckpointEvidence to captureQuestion it answers
before connectapp screenshot, web address (URL), available wallet stateDid the app offer the right connection path?
after connectselected account in app and wallet, provider responseAre both sides using the same account?
after network requestrequested and selected chain identifiersDid the app ask for the intended network?
before signquote, token, amount, spender or contract, wallet promptWhat would the user approve?
after rejectwallet rejection, provider error, app error stateDid the app recover without claiming success?
after test transactionreceipt or local-chain result, app state, balanceDoes the page reflect the chain result?
stopfinal screenshot, terminal status, reasonWhy did the test end?

Store sensitive values according to the test environment’s retention policy. Redact private keys, seed phrases, session cookies, and personal addresses that the reviewer does not need. Keep enough account and chain context to distinguish a wrong fixture from a product defect.

Inspect accountsChanged, chainChanged, and provider error 4001

An EIP, or Ethereum Improvement Proposal, is a public specification for an Ethereum interface or protocol change. The EIP-1193 provider specification defines a common JavaScript API, or application programming interface, between an Ethereum web application and a wallet or client. Its request method returns a result or rejects with a provider error. Its events include connect, disconnect, chainChanged, and accountsChanged.

Those events are test signals. If the chain changes, the app should update its network state. If the account changes, the app should update or invalidate account-specific state. If a request is rejected with code 4001, the app should treat it as user rejection rather than as successful approval.

Typed signing uses structured data rather than an opaque byte string. The EIP-712 standard defines typed data, a domain separator, and a signing method designed to let wallets present meaningful fields to users. It explicitly does not provide replay protection by itself. The dapp and contract still need a nonce, or one-use counter, expiry, chain binding, or another replay policy appropriate to the operation.

An illustrative provider listener can make the app-side evidence explicit:

type ProviderError = Error & { code?: number; data?: unknown }

const provider = window.ethereum

if (!provider) {
  throw new Error('No injected wallet provider was found')
}

provider.on('accountsChanged', (accounts: string[]) => {
  console.log({ event: 'accountsChanged', accounts })
})

provider.on('chainChanged', (chainId: string) => {
  console.log({ event: 'chainChanged', chainId })
})

try {
  const accounts = await provider.request({ method: 'eth_accounts' })
  const chainId = await provider.request({ method: 'eth_chainId' })
  console.log({ accounts, chainId })
} catch (error) {
  const providerError = error as ProviderError
  console.error({
    message: providerError.message,
    code: providerError.code,
    data: providerError.data,
  })
}

This is an illustrative browser-side example based on EIP-1193. The MetaMask Connect software development kit is MetaMask’s connection software for choosing supported wallet environments. An application using MetaMask Connect or another wallet library may expose a different integration object. The test should observe the public behavior that the application relies on, not assume that every wallet uses one implementation.

Test rejected, pending, reverted, and stale states

Create a small matrix before adding many actions.

Starting stateExpected application behaviorRequired evidence
no wallet extensionexplain supported connection methodsapp screenshot and stop reason
wallet access is unavailablerequest access or stop the caseprompt or blocked state
wrong chainrequest a switch or block the actionrequested and selected chain
account changedrefresh account-specific data or require reconnectaccount event and app state
empty test balanceprevent submission or explain the missing balancebalance state and disabled action
rejected signatureshow a recoverable error and keep the quote state honestprovider error and app screenshot
pending transactionshow pending without claiming completiontransaction identifier and pending UI
reverted transactionshow failure and preserve retry contextreceipt or local-chain result
stale allowanceshow the requested spender and allowance changeapproval prompt and post-action state

Asset symbols and shortened addresses can hide a wrong contract target. An asset symbol in the app can differ from the contract address the transaction targets. A shortened address can hide the wrong contract. A friendly route name can conceal a different path after the quote expires. Capture the raw identifiers where a reviewer needs them, and show the human-readable prompt where the user makes the decision.

Separate approval from settlement

Wallet flows often collapse several statuses into one button label. A request can be created without being signed. A signature can be returned without a transaction being broadcast. A broadcast transaction can remain pending. A mined transaction can still revert.

Keep those states distinct in the case:

StateMeaningEvidence
requestedthe dapp asked the provider or wallet to actprovider request and page context
presentedthe wallet displayed the approvalwallet prompt screenshot
rejectedthe user or wallet declined the requestprovider error and app recovery
signeda signature or transaction authorization was returnedresponse record in a test environment
broadcastthe transaction reached a chain clienttransaction identifier and RPC result
pendingthe chain has not produced the expected confirmationpending UI and subsequent observation
confirmedthe owning system reports the expected resultreceipt, event, or application-owned confirmation
failedthe request or transaction produced an errorerror details and truthful app state

The case may stop at any of these states. For a smoke test, stop at presented unless signing is explicitly authorized. Continuing to confirmed requires a controlled wallet, a known chain, test funds, and a check owned by the chain or application rather than by the model’s description.

Run the Tangle driver at the browser boundary

The live Browser Agent manifest names the package, the bad binary, and the documented safe discovery commands. The public driver README includes a wallet and DeFi testing section.

npm install -g @tangle-network/browser-agent-driver
npx playwright install chromium
bad --help
bad run \
  --url https://app.example.com \
  --goal "Connect the disposable wallet, verify the configured test chain, enter a small swap quote, capture the wallet prompt, and stop before signing"

The URL and wallet are illustrative. Run against a staging app, local chain, or another environment with test funds. Do not pass a production storage state or seed phrase to an exploratory agent.

The runtime is the environment that contains the browser process, model calls, files, network access, and wallet fixture. Record its browser version, extension version, chain endpoint, account class, and reset method. An agent profile is the named model, observation mode, permissions, turn limit, and stop policy used for the run. Record the model, observation mode, permissions, turn limit, and stop policy beside every run. Compare runs with identical settings before attributing prompt differences to the application.

Separate page, wallet, provider, and chain evidence

Browser Agent can run as a local package and CLI without the service-packaging layer described by Tangle Blueprints. If a team offers wallet testing as a service, a Blueprint can define the job inputs, runtime requirements, and returned artifacts, while an operator is the provider that runs the job. The Blueprint records Job inputs, runtime requirements, returned artifacts, and operator responsibility. It does not validate a wallet prompt, a contract, or a chain result.

Return application state, wallet state, provider responses, and chain confirmations as separate evidence fields so a reviewer can see which boundary produced each claim.

What browser wallet testing does not prove

A browser run can prove that a particular application and wallet fixture presented a particular flow. It cannot prove smart contract safety. It cannot replace contract tests, transaction simulation, audits, monitoring, or chain-level accounting. It cannot prove that a live-network transaction will settle at the quoted price. It cannot prove that a wallet extension version will preserve the same UI. It cannot make a signing action safe merely because a model reached the prompt.

The strongest claim is narrow: under a recorded runtime and disposable fixture, the application showed the expected wallet state, the wallet showed the expected approval details, and the app reported the resulting state honestly.

What is DeFi wallet testing?

DeFi wallet testing checks a finance application across the web page, wallet extension, provider, chain, and user approval boundary.

Why is it harder than ordinary browser testing?

The decisive state can live outside the page. The application can show one account or chain while the wallet prompt shows another. The test must capture both sides.

What is the minimum evidence?

Capture the starting app state, selected account, chain identifier, wallet prompt, action log, provider error or transaction result, final app state, and stop reason.

Should a browser agent sign transactions?

Only in a controlled test environment with a disposable wallet, test chain, non-production credentials, and an explicit policy that permits the action. Otherwise stop at the signing prompt.

Does this replace a smart contract audit?

No. It tests the user flow around contract interactions. It does not establish that the contract logic or economic design is safe.

Set the approval boundary before you automate

Use a browser agent to inspect application state, wallet prompts, network changes, and recovery behavior. Use deterministic tests and chain-level tools for contract invariants and transaction semantics. Accept a wallet-flow result only when a reviewer can see the account, chain, requested action, outcome, and reason the run stopped.