* fix(wallet): poll receipts on the node that took the broadcast
Chain 1 now proxies to the same `/alchemy` path `nodes.broadcastTransaction`
and `nodes.getNonce` use. A node that does not hold the transaction answers
receipt lookups with null forever.
* fix(wallet): only commit the nonce on a validated broadcast
The result was read unvalidated, so a broadcast that produced no transaction
still burned its nonce and gapped every later one. Failures now carry the
node's own reason instead of the status code.
* fix(wallet): reconcile the nonce down against an empty pool
Nothing lowered the local counter, so one dropped transaction left every
later one signed at a gapped nonce until the browser restarted. When the
node's pending and latest counts agree it holds nothing for the account, so
a counter above that is lowered once it has stayed ahead for 5 blocks.
* feat(wallet): detect and notify dropped transactions
A never-mined transaction kept its 30s alarm forever, since only receipt
`0x1` and `0x0` settled it. `eth_getTransactionByHash` is now the probe: a
null receipt means nothing on its own, but three consecutive polls where the
node has no record of the hash settle it as dropped. RPC failures do not
count towards that.
* fix(wallet): sync pending transactions from the background monitor
The page read the list once at mount and wrote its own copy back over the
monitor's removals, leaving settled transactions pending. It now watches the
key it shares with the monitor.
* fix(wallet): keep the earliest mark for a pending count
The post-send mark overwrote the block a held one carried, so every send
from the address restarted the 5-block window and the counter was never
lowered -- each retry only added another gapped transaction. `resolveNonce`
now reports when a mark for the pool count is already held.
* fix(wallet): read gasUsedRatio as a float
`eth_feeHistory` returns it as a float, so `parseInt(hex)` stopped at the
decimal point and `averageGasUsedRatio` was always 0, pinning the ETA to
the idle branch. Also guard the empty-history average against NaN.
* fix(wallet): floor the tx tip and raise the fee ceiling
Tip is now max(eth_maxPriorityFeePerGas, feeHistory p50, 1 gwei); the
suggestion alone ran ~270x under the median tip paid and `0x0` was
signable. Ceiling goes 2x -> 3x base fee, ~14 -> ~23 blocks of headroom
before the tx becomes unincludable.
* fix(wallet): lower the tip floor to 0.1 gwei
1 gwei sat ~16x over the median tip paid at a ~0.11 gwei base fee, so it
set the quoted price rather than backstopping it. Only quiet markets
change: above 1 gwei the tip is max(suggestion, p50) either way, leaving
congested sends and LiFi swaps untouched.
* feat(wallet): add a chain registry
One source for chain id, name, icon, viem chain, proxy route and whether
sends are possible, replacing three lists that disagreed: the switchable
set in rpc/chain.ts, the mainnet pin in public-client.ts and the
name/icon maps in the approval popup.
No upstream proxy path is known for Status Network Sepolia, so it ships
with proxyChainId null.
* refactor(wallet): resolve chains through the registry
Drops the duplicate SUPPORTED_CHAIN_IDS set, the SIGNABLE_CHAIN_ID
constant and the CHAIN_NAMES/CHAIN_ICONS maps.
Chain ids are matched by value rather than by string, so 0x6300B5EA and
0x6300b5ea stop being two chains, and the registry's spelling is what
gets stored.
* feat(wallet): route dApp reads to the origin's chain
Forwarded reads went to a module-level mainnet client whatever chain the
dApp had switched to. getPublicClient memoizes one client per chain over
that chain's proxy route.
A chain with no route is refused with 4901, not 4902: it is recognised
and switchable, so 4902 would invite an add-and-retry that succeeds and
then fails the same way.
* test(wallet): cover multi-chain read routing
* chore(wallet): add changeset
* chore(wallet): drop redundant comments
* refactor(wallet): convert the origin chain id through the registry
The typed-data chain check used parseInt, which toChainId exists to
replace: it reads a bare '1' or a trailing-garbage '0x1zzz' as mainnet,
so a malformed id would compare equal to a chain it is not. Nothing
reaches the check with a non-canonical id today, so this is the
invariant landing in one place rather than a behaviour change.
The mismatch message now names the chain, falling back to the raw hex
so an unrecognised id does not print as NaN.
* fix(wallet): keep dApp connections until explicitly revoked
Move permissions from chrome.storage.session to local, keyed per origin and
per account. A browser restart, a page reload or an account switch no longer
drops a connection -- only wallet_revokePermissions or the wallet's own
Disconnect action does.
Each origin is pinned to the account it was connected with, so switching
accounts exposes the new account only to dApps already connected to it and
pushes accountsChanged to their tabs. eth_accounts, eth_requestAccounts and
personal_sign all resolve through that pinned account.
* fix(provider): stop tearing down the dApp session on reload and errors
A fresh provider restores its session from eth_accounts rather than reporting
itself disconnected, close() no longer revokes the stored permission, and an
RPC error whose message reads "dApp is not permitted by user" no longer
disconnects. isConnected() reports transport readiness per EIP-1193 instead
of account state.
Adds a window listener for accountsChanged pushed by the wallet, so an
account switch reaches the page without a reload.
* feat(wallet): add dApp connections menu
Lists connected dApps behind their own trigger beside the wallet selector.
Each entry shows the account that dApp sees, offers Connect for the selected
account when it is not connected there, and Disconnect.
* fix(wallet): stop the approval popup rendering an empty window
The mount effect awaited the pending approval and the session status with no
rejection handling, so either one failing left the popup at `return null` --
a white window with no way out. A cold service worker rejecting the first
port message is enough to trigger it. Both reads are now guarded, and a
missing request renders an explicit "no longer available" state.
Claim the single approval slot synchronously as well. The stored record is
read asynchronously, so two requests in the same tick both saw it empty and
each opened a popup, then overwrote each other's record.
* fix(wallet): count approval popups in the mock instead of casting
The spy cast an async wrapper to the overloaded chrome.windows.create type,
which tsc rejects. The mock already owns that call, so it counts there.
* chore(wallet): add changeset
* fix(wallet): preserve trpc error messages over the chrome transport
trpc-chrome posts error shapes verbatim but its link deserializes them
with the configured transformer; with superjson every error collapsed to
"Unknown error". Pre-serialize the shape in errorFormatter so messages
round-trip.
* feat(wallet): extract derivation path helpers
Add pathAtIndex and nextDerivationPath so the next sequential path can
be computed without deriving keys; cover with unit tests.
* feat(wallet): add and preview derived accounts by wallet id
Extend wallet.account.ethereum.add with an optional custom derivation
path, a mnemonic-only guard, duplicate rejection, and selection of the
new account. Add wallet.account.ethereum.preview to derive an address
(next sequential or custom path) without persisting; the mnemonic stays
in the background session.
* feat(wallet): create account flow from the wallet selector
New /wallet-flow/add-account route: prefilled next sequential derivation
path, editable to a custom path, with live address and activity preview
before confirming. Entry point in the wallet selector dropdown, mnemonic
wallets only.
* chore(wallet-extension): make create account button full width
* fix(wallet): restore mobile wallet selector interaction
Allow clicks to pass through the transparent sticky header until its controls are visible.
* chore(community-dapp): add .env.example
Document webpack build-time env vars for local dev and deployments.
* chore(community-contracts): update .env.example
Add ETH_FROM, API_KEY_OPTIMISM, and usage comments for forge deploys.
* fix(community-dapp): correct build paths relative to vercel root dir
buildCommand ran 'cd apps/community-dapp' and outputDirectory used
'apps/community-dapp/dist', but the build cwd is already the app dir
(vercel root directory), so the cd failed. Use paths relative to the
root dir.
* fix(community-dapp): build contracts during vercel build
abi/index.ts imports forge-generated ABIs from community-contracts/out,
which is gitignored and absent on vercel. The custom buildCommand calls
webpack directly, bypassing the prebuild hook that runs forge build.
Init the contracts submodules, install foundry, and run forge build
before webpack so the ABIs exist.
* fix(community-dapp): move vercel build into a script
The inline buildCommand exceeded vercel's 256-char limit. Move the
contract-build + webpack steps into scripts/vercel-build.sh and call it.
* chore: add changeset
* chore(community-dapp): trigger build
* fix(status.app): normalize prefetch before passing to next-intl Link
next/link can emit prefetch: "unstable_forceStale", but next-intl’s Link type doesn’t accept it. Strip/normalize that value in the shared link wrapper to prevent the TypeScript build error.
* chore: upgrade next to version 15.5.16 across all projects
* chore: re-generate next-end.d.ts
* chore: add changeset
* fix(wallet): revalidate price chart cache on first stale read
Next.js fetch cache uses stale-while-revalidate, so the first request
after the window returned a stale snapshot (hours old after idle) and
only refreshed in the background. Bucket the fetch URL by the
revalidate window so the first request in a new window is a cache miss
and fetches fresh synchronously. Applied to fetchTokenPriceHistory and
fetchTokensPrice via a shared setRevalidationBucket util.
* chore: add changeset
* chore(wallet): re-enable token value chart
* chore: add changeset
* feat(wallet): append latest spot and balance chart points
Ensure token charts include current spot price and current balance snapshots so rightmost points reflect fresh data.
* chore(wallet): align wallet query stale defaults
Set wallet fallback and token chart query stale windows to one minute to keep list and token views refreshed on the same cadence.
* feat(wallet): refresh token chart queries from toolbar
Include active price and balance chart queries in manual wallet refresh so token view latest values update immediately.
* chore(wallet): decrease short RPC requests rate-limit
From 30 RPM allowed to 40 RPM allowed
* chore(wallet): clean magic numbers in asset-chart
* feat(wallet): extract buildCanonicalTimestamps utility for uniform chart grid
* fix(wallet): anchor balance history grid at now and walk backward
Replaces the forward-walking timestamp loop (which had an uneven final gap
patched by pushing currentTime at the end) with buildCanonicalTimestamps.
The grid is now anchored at anchorTime (currentTime || now) and walks
backward in fixed intervals, so every gap is identical and the first point
is always exactly the anchor time.
* feat(wallet): add server-side tokenValueChart and nativeTokenValueChart procedures
Computes value (price x balance) on the canonical timestamp grid server-side,
replacing the client-side binary search in useValueChartData. Both procedures
share the same grid as the balance chart, so all three chart types have
homogeneous time gaps.
Key changes:
- Add tokenValueChart / nativeTokenValueChart async functions with shared
buildStepBeforeLookup and buildValuePoints helpers
- Register both as tRPC procedures on assetsRouter
- Remove LATEST_BALANCE_POINT_OFFSET_MS hack and the duplicate
getERC20TokensBalance / getNativeTokenBalance calls that appended a
current-balance point at now-60s
- First point always uses live spot price + balance (same sources as
assets.all) to prevent drift with AssetsList
* feat(wallet): query server-side value chart in AssetChart; remove useValueChartData
Adds a dedicated valueChart query that calls assets.tokenValueChart or
assets.nativeTokenValueChart. Loading and error states for the value tab now
derive solely from that query. Removes useValueChartData and the client-side
price x balance computation it performed.
* fix(wallet): forward-fill price lookup prefix to avoid $0 first value point
The canonical timestamp grid for value charts can extend slightly before the
earliest sample returned by CoinGecko's price history. In that case the
step-before lookup returned 0 for the oldest timestamp, producing a spurious
$0 value at the left edge of the chart. Fall back to the earliest known value
when the query precedes all data points.
* fix(wallet): show "No value" empty state only when address never held the asset
The value chart endpoints now return [] when no transfers exist at any point
in the address's history (mirroring the Balance chart's behavior). For any
asset the address has held at some point, every timeframe renders a full
chart, even if the value sits at 0 for that window.
* fix(packages/wallet): force-cache causing priceChart to return stale data
force-cache was causing `tokenPriceChart`/`nativeTokenPriceChart` calls to return stale data (for multiple days!). Using revalidate only still ensures coingecko price history data (`fetchTokenPriceHistory`) to be correctly cached for the revalidation time duration (1 hour).
* refactor(wallet): extract padHex to shared package
Move the hex-padding utility out of ethereum.ts into @status-im/wallet/utils
so it can be consumed by both the signing layer and the nonce tracker.
* refactor(wallet): extract tRPC helpers to shared utils module
Move buildTrpcUrl, fetchTrpcData, and extractTrpcErrorMessage from
token-helpers.ts into apps/wallet/src/utils/trpc.ts so they can be
imported by any module without pulling in token-specific logic.
* fix(wallet): replace ad-hoc nonce tracker with mutex-scoped reservation
The old localNonceTracker bumped the nonce before broadcast, so a failed
broadcast left the counter permanently ahead, breaking every subsequent tx
until the extension reloaded. Concurrent dApp-bridge requests also raced on
the same counter and could both use the same nonce.
Replace it with a per-address mutex (promise-chain) that only commits the
incremented nonce after the broadcast callback resolves. Nonces are persisted
to chrome.storage.session via @wxt-dev/storage so the counter survives
popup reloads without losing progress.
* feat(wallet): add gas fees hook with polling and pre-sign refresh
Extract gas fee fetching into useGasFees with a 12s refetch interval and 8s
stale time so estimates stay current while the user reviews the modal.
Add checkAndRefreshGasFees(), called at sign time, which forces a fresh fetch
and returns the latest params. This ensures the broadcast always uses
up-to-date maxFeePerGas/maxPriorityFeePerGas regardless of how long the
user spent on the confirmation screen.
* feat(wallet): gate large gas price shifts with user confirmation
If gas rises >=30% between estimate and sign, checkAndRefreshGasFees throws
GasShiftedError. The send modal catches it, enters a 'gas-shifted' state, and
shows an inline warning with a 'Confirm with new gas price' button. A second
click resumes signing with the fresh params.
Smaller gas bumps (<30%) are accepted silently — the broadcast proceeds with
the refreshed values without user interaction.
* feat(wallet): expose imperative fetchGasFees from useGasFees hook
Stable callback for non-React callers to fire a one-off gas-fee
request without driving the reactive query. Accepts a data field
for arbitrary contract calls.
* refactor(wallet): replace 3-fetch gas fallback with single nodes.getFeeRate call
Drop the eth_getBlockByNumber + eth_maxPriorityFeePerGas + eth_estimateGas
trio in signAndSendTransaction in favor of one fetchGasFees call from the
useGasFees hook. Caller-supplied fee fields are now preserved per slot
via ??= instead of being overwritten as a pair.
* chore: add changeset
* feat(wallet): restore configurable gas limit buffering
Restore the 10% gas-limit safety margin via useGasFees (replacing the behavior removed from signer-context) and allow callers to disable it for native ETH transfers.
* chore(wallet): update li.fi widget
* fix(wallet): use our custom RPC proxy instead of public RPC
Many JSON RPC were made to a public API instead of our private RPC API. This included the ones made by Li.Fi, which was causing rate-limiting on the widget.
This commmit also factorizes the use of viem PublicClient to not instantiate more than needed.
* fix(wallet): handle batch JSON-RPC requests
* refacor(wallet): create singleton for viem publicClient
* chore: add changeset
* chore(wallet): move extractTxHash to package
Factorize all get tx hash operations to the package wallet and extract eth tx hash check to package as well.
* chore(wallet): replace `extractTxHash` by `getTransactionHash`
`getTransactionHash` is more robust and exported form the wallet package. Import `getTransactionHash` from the same location everywhere and remove re-exports. Delete `tx-helpers.ts` since not used anymore.
* fix(wallet/build): revert back to relative import
* fix(wallet): disable interation w/ sticky header
* feat(wallet): persist selected account and normalize legacy data
Extend wallet metadata & API with selected account persistence and normalization for legacy activeAccounts
* feat(wallet): expose and persist current account in provider
Update WalletProvider to expose/select current account and persist selections
* refactor(wallet): use selected account in portfolio and signer flows
Replace first-account assumptions in portfolio and signer flows with selected account
* feat(wallet): implement wallet selector UI
Implement wallet selector UI and integrate into splitted layout
* chore(wallet): update import and create hooks to match api
Update import and create wallet hooks to use optional password to match new API props
* feat(wallet): componentize create/import flows
Componentize create/import flows and create non-onboarding cases
* refactor(wallet): use components for onboarding flow
Use previously componentized flows for create/import wallet onboarding flows
* feat(wallet): add standalone create and import routes
Add create/import wallet routes for non-onboarding flows. Enables wallet setup outside of the initial onboarding flow
* chore: add changeset
* chore(wallet): hardcode account name for dapp connect
* chore(wallet): comment out account name tooltip
Comment current account's name tooltip displayed on address hover. Since multi-account support is not implemented yet, this feature is more confusing than helpful.
* chore(wallet): add TODO for multi-account support
* chore(wallet): use wallet name instead of account name
Replace all use of currently selected account name by currently selected wallet name. The purpose is to avoid any confusion in the UI/UX between accounts and wallets.
* chore(wallet): rename wallet-account-selector to wallet-selector
Since we don't have multi-account support right now, rename to wallet-selector to make it explicist and avoid any confusion.
* fix(wallet): remove `/wallet-flow` as a route
There was no point in having `wallet-flow` as an existing route, it was a mistake.
* chore(wallet): remove useless refetchQueries
invalidateQueries will already handle the refetch for active queries.
* chore(wallet): edit create-password-step to factorize code
* fix(wallet): rename legacy "Account 1" wallets to "Wallet N"
Legacy wallets stored with the default name "Account 1" are now
automatically renamed to the next available "Wallet N" during
normalization. The rename is persisted to the store so it only
runs once per legacy wallet.
* feat: migrate community dapp
* fix: change server protocol from https to http in webpack config
* fix: update build script in package.json and add output directory to turbo.json
* fix: update CI workflow to initialize git submodules recursively and add Foundry installation step
* chore: change from community to community-dapp
* feat: add global type declarations for wallet and API integration
* fix: correct syntax for not-first-child selector in Card component
* fix(wallet): use type-safe globalThis cast instead of direct property assignment
* fix(community-dapp): fix eslint FlatCompat config and include test files in tsconfig
* fix(ci): fix forge test args and disable broken community-dapp tests
* fix(community-dapp): resolve @libp2p/interface to v2.10.4 for webpack build
* fix: add @libp2p/interface as missing dependency for @waku packages via packageExtensions
* fix: address PR review feedback
* fix(wallet): restore type-safe globalThis cast for CI build
* fix: commit ABI artifacts and add vercel.json for SPA routing
* fix(community-dapp): add 404.html for SPA routing on Vercel
* fix(community-dapp): simplify vercel.json to rewrites only
* fix(community-dapp): update vercel.json with build and output configurations
* fix: add Foundry dependencies to .gitignore
* feat(unstake-vault): improve max balance handling and precision truncation
* fix(hub): truncate unstake MAX amount to 6 decimals to prevent precision overflow
* feat(lock-vault): enhance lock functionality with error handling and user feedback
* fiix: adjust lock time calculation to account for block time drift
* feat(unstake-vault): allow clearing input for amount field in unstake modal
* fix(lock-vault): improve timestamp handling and buffer calculations for lock extension
* fix(lock-vault): add loading state to lockUntil data retrieval and disable action button accordingly
* feat(lock-vault): enhance lock functionality with query invalidation and improved extension logic
* fix(lock-vault): handle bigint serialization in query invalidation to prevent stale cache issues
* fix(lock-vault): adjust remaining days calculation and clean up unused code in lock vault form
* feat(lock-vault): add max days validation based on MP cap and enhance loading state handling
* fix(lock-vault): implement safety cap for increased lock duration and simplify query invalidation
* fix(lock-vault): remove unused MP cap validation logic and clean up related code
* fix: register community-contracts submodules in .gitmodules
* feat: add wagmi, viem and @lifi/widget dependencies
* feat: add ethereum contract call and signing API functions
* feat: add sendContractCall ethereum wallet function
* feat: add signer context for wallet password and transaction signing
* feat: add custom wagmi status connector
* feat: add wagmi provider setup
* feat: add exchange drawer UI component
* feat: integrate LiFi widget for token swaps
* feat: update root route with new providers
* feat: add exchange button to token component
* chore: update CSP and improve password modal accessibility
* feat(wallet): enhance exchange drawer UI
* feat: add password context provider
* feat: extend password modal with customizable props
* feat: integrate password provider in root
* feat: integrate password context in onboarding flows
* feat: integrate password context in exchange drawer
* feat: integrate password context in send assets modal
* feat: integrate password context in recovery phrase backup
* refactor: migrate signer context to use password context
* chore(wallet): update lifi, wagmi & viem versions
* chore(changeset): revert useless quotes change
* chore(changeset): remove useless formatting change
* chore(wallet): remove useless async prefix
* chore(wallet/status-connector): turn code handling provider requests into a function for better readability
* chore: add changeset
* fix(wallet): properly type status-connector connect method
* chore(wallet/exchange): update request password modal copy
* chore(packages/wallet): delete SignTransactionDialog dialog as it is now dead code
* chore(apps/wallet): rename usePasswordSession to usePassword
* chore(apps/wallet): remove unnecessary async/await in password-context
* chore(wallet): remove unused import
* chore: add changeset
* chore(wallet): remove unnecessary await
* feat(wallet): show insufficient funds error when user is missing funds
* fix(wallet): white page after onboarding
* fix(wallet): redirection to `/portfolio/assets` when opening wallet UI
If user is onboarded and closes then opens the wallet's UI, he would be shown the onboarding page. This is has been fixed
* feat(wallet): add browser-passworder dep and alarms permission
* feat(wallet): add vault encryption service
* feat(wallet): add wallet metadata store
* feat(wallet): add stateless key derivation helpers
* feat(wallet): add session manager with auto-lock and migration
* feat(wallet): add alarm listener for session auto-lock
* refactor(wallet): replace keystore with session-based vault
* chore(wallet): remove useless no-op method
* chore(package/wallet): change toasts on tx send & enable sign btn after tx success
* fix(wallet): add chrome.alarms mocks to fix failing tests
* fix(wallet): migrate remaining legacy wallets on every unlock & delete them
Run migration on every unlock to ensure wallets that use different passwords get migrated when user access them.
* chore(wallet): remove unsued type field
* chore(wallet): make variable name more explicit
* refactor(wallet): make password request flow return boolean
Also changed variable names of callers to isUnlocked to be more explicit.
* chore(wallet): invalidate gql query so it would not stale
* fix(wallet): unblock send CTA during gas fee refetch and clarify action label
* fix(wallet): send tx & nonce padding && nonce collision && broadcastTx JSON extract
* fix: improve handling of feature images in blog detail page
* feat: enable direct URL access for hidden desktop-news and mobile-news blog posts
* feat: clean up sitemap configuration and add blog posts with publish dates
* feat: clean up sitemap by removing unnecessary fields and adding actual publish dates for blog posts
* feat: add status.network#build task with environment variables for Ghost API
* feat: clean up sitemap by removing unnecessary fields and ensuring accurate publish dates for blog posts
* feat: remove deprecated changesets for sitemap cleanup and blog post accessibility
* feat(blog): add blog to status.network
* refactor(blog): simplify blog page by removing unused tags and links
* feat(metadata): enhance JSON-LD schemas for Status Network with additional properties and improved descriptions
* chore: add changeset for JSON-LD schema updates, layout adjustments, and UI tweaks across components
* feat(blog): include status-network-blog in disallowed tags and update filters for post retrieval
* feat(blog): implement BlogCard component and update blog to fetch posts dynamically by tag
* feat(naver): add Naver blog integration with RSS fetching and image proxying
* feat(naver-image): implement Naver image handling functions and integrate with API route
* feat(ghost): enhance post retrieval by filtering disallowed tags and adding tag validation
* feat(blog): implement blog section with dynamic routing and metadata
* chore(blog): remove revalidation setting from blog page
* fix(blog): update environment variable names for Ghost API configuration
* feat(blog): enhance blog detail sharing by encoding post title in tweet URL
* fix(blog): update fallback image path in blog detail and post card components