If you held a Hong Kong listed xStock in July, your SolanaRWA portfolio showed it at $0.00. Not because the token was worthless, and not because we had failed to detect it. The dashboard knew exactly what it was, which issuer minted it and what company it wrapped. It just refused to put a price on it.
Backed Finance spent the first half of 2026 expanding well past the US large caps that xStocks launched with. Hong Kong, London, Frankfurt, Milan, Madrid, Seoul. Hundreds of new mints, all live on Solana, all picked up by our wallet scanner, and about 600 of them sitting in real portfolios at zero.
This is the story of why we left them there for a while, and what it took to price them properly. The registry went from 616 tokens to 1,202 across 27 protocols. The interesting part is not the number. It is the specific ways this goes wrong if you move fast.
The Number That Is Worse Than Zero
Yahoo Finance is our fallback price source when Jupiter cannot quote a mint, which is the case for most international listings. Ask it about Vodafone and you get this: VOD.L, 117.1. Read that as dollars and a holder's Vodafone position gets recorded at $117.10 a share.
The real number is about $1.59. Yahoo quotes the London listing in GBp, which is pence, not pounds. The figure is off by a factor of 75, and nothing about it looks wrong. It is a plausible price for a plausible stock, sitting in a plausible portfolio.
Now follow it downstream. Portfolio totals are denominated in USD. Capital gains maths is USD. The CSV and the PDF you hand your accountant are USD. A $0 line item is visibly incomplete, and sooner or later somebody asks about it. A $117.10 line item quietly inflates a tax return by 75x and nobody notices until a revenue office does.
That is the entire reason those 600 mints sat unpriced for months. A missing number announces itself. A wrong number does not.
Failing Closed, On Purpose
There is now exactly one place in the codebase where a non-USD figure becomes a USD one, and it enforces three rules.
First, an allow-list. 33 currencies, every one confirmed against a live Yahoo FX pair before it went in. An unknown or missing currency code returns nothing and logs loudly. There is no "assume USD" fallthrough anywhere in the module, and that absence is deliberate enough to be written into the docstring, because it is precisely the shortcut that would reintroduce the pence bug at some future 2am.
Second, minor units are handled before conversion, not after. GBp is pence. ZAc is South African cents. ILA is Israeli agorot. Each one needs a divide-by-100 on top of the exchange rate. The lookup table is case-sensitive, and it has to be: GBp and GBP differ by a single letter and a factor of 100.
Third, the price and the rate come from the same source on the same day. Mixing a Yahoo quote with a rate from somewhere else introduces a timing skew that is impossible to reconcile after the fact, and the discrepancy would only ever show up in a filed return.
The Rounding Trap
One detail cost more debugging than the rest of the module combined, and it is the kind of thing you only find by checking your own output against reality.
The obvious way to get an exchange rate is to ask for the pair you want. Need Korean won in dollars? Fetch KRWUSD=X. It returns 0.0007.
That is rounded to four decimal places, which for a low-value currency destroys the number. SK Hynix at 1,712,000 KRW times 0.0007 gives $1,198. The true figure is about $1,243. Three percent out, on every Korean holding, every day, permanently, and entirely invisible because $1,198 is a completely reasonable-looking number.
The fix is to fetch the pair the other way around. USDKRW=X returns 1375.88, and inverting that keeps full precision. So the service always fetches USD against the target currency and inverts, never the direct pair. Rates cache per UTC date and fetch single-flight per currency, so a valuation run across hundreds of Hong Kong tickers makes exactly one FX call.
Six Hundred Tickers, Resolved One at a Time
With conversion made safe, the remaining problem was mapping each mint to the right Yahoo ticker. Backed names them predictably, so TSLAx points at TSLA. That works until it does not, and the failure modes are specific enough to be worth naming.
Cross-listings. Ask Yahoo about Altria and six candidates come back across four currencies, because German regional exchanges, the Mexican SIC, Brazilian BDRs, Argentine CEDEARs, Thai DRs and Singapore depositary receipts all carry quotes on foreign issuers. None of them is the security the token wraps. Our resolver discards those by venue while deliberately keeping XETRA, Milan, Madrid, the LSE, HKEX and KRX, because those are primary markets for their own issuers rather than venues for somebody else's.
ADRs versus ordinaries. This is the expensive one, and Vodafone is the case that proves it. VOD on NasdaqGS trades at $15.88. VOD.L in London trades at 117.1 GBp, about $1.59. Both are Vodafone. They differ by a factor of ten, because one ADR bundles ten ordinary shares.
We caught it with a sanity check rather than outside knowledge. Price times on-chain supply should put a wrapper somewhere near its peers, and the accepted set clusters tightly: median around $6.08M, tenth percentile $2.88M, ninetieth $7.87M. Taking the Vodafone ADR would have produced a $48.6M wrapper, more than twice the largest thing in the entire set, against a true $4.88M. Any ticker whose base symbol exists in two currencies now goes to manual review, without exception.
Name matching. Comparing issuer names word by word rather than by substring is what stops Telefonica from resolving to Telefonica Brasil, a different company at a different price. It scores 0.85 against the threshold and gets rejected, which is the correct outcome even though the names look nearly identical to a human skim.
Then We Checked All 942
513 mints resolved cleanly, 462 in USD and 51 in Hong Kong dollars. 73 went to manual review and were worked by hand, every pick verified live and put through the market-cap band. 15 remain unresolved and need a data source Yahoo does not have.
Then we did the part that is easy to skip. A separate audit script reads the registry off disk, asks Yahoo about every single ticker in it, and reports what comes back. Not just the new entries. All of them.
942 of 942 priced. Zero currency mismatches, zero unresolvable, zero throttled. The currencies returned were 868 USD, 73 HKD and 1 GBp, which is exactly the split the registry declares, so nothing had quietly resolved to a listing other than the one it names.
That pass also caught something old. BRKBx carried the ticker BRK.B, which Yahoo does not recognise, because the Berkshire class B share is written BRK-B. That price fallback had been dead since the day the entry was written, masked the entire time by Jupiter happening to price the mint through another route. The currency work did not break it. The audit simply made it visible for the first time.
The script is repeatable and it gets run after every registry backfill now. Pricing fails closed, which is the right trade, but it means an asset can drop to $0 without anything looking broken. "Is anything silently at zero" deserves a measurement rather than an assumption.
What Changes If You Hold One
Nothing you need to do. If your wallet holds a Hong Kong, London or European xStock, it now carries a real USD value in your portfolio, your allocation breakdown, your history chart and your tax exports. The daily valuation job warms the exchange rate for every currency the registry declares before it starts pricing wallets, so conversion costs one lookup rather than one per asset.
If something you hold still shows $0, that is now informative rather than ambiguous. It means we genuinely cannot price it, not that we are guessing badly. The 15 unresolved mints are in that bucket, and pre-IPO PreStocks always will be, because a private company has no listing for anyone to quote.
Registry entries carry a currency assertion as well as a ticker. If a mint declares GBp and Yahoo starts returning USD, that means the ticker has resolved to an ADR somewhere along the way, and the price gets rejected rather than converted. The assertion is a cross-check, never a default. Absence of one means no assertion, not "probably USD".
Also Shipped This Month
The swap page token picker was rebuilt as a modal. An inline grid with every category expanded was fine at 20 tokens and a wall at 60, and it pushed the Jupiter widget below the fold on a phone. Now you see the selected token and a Change button, with search that ranks by exact ticker, then ticker prefix, then the start of a word in the company name, so typing "sp" surfaces SPY rather than an incidental mid-word match.
Pre-IPO tokens whose underlying company has since listed now carry a "Now public" badge directly in the list, with a pointer to the public wrapper to trade instead. That badge exists because the explanation previously appeared only once you selected the row, which meant anyone scrolling past saw SPACEX looking identical to every still-private pre-IPO token.
The Bottom Line
There is a version of this project where international pricing shipped in an afternoon: read the Yahoo number, write it to the database, move on. It would have worked for the US listings, which are most of them. It would also have been wrong by a factor of 75 on Vodafone, by three percent on every Korean holding, and by ten times over on anything where the resolver grabbed an ADR by accident.
A portfolio tracker can afford to be roughly right. A tool that generates the numbers you actually file cannot. So the rule we settled on is that a price we cannot verify does not get written at all, and $0 stays an honest answer to a question we cannot yet answer.
Connect a wallet at solanarwa.app and see what your international holdings are genuinely worth. Portfolio tracking is free, tax exports are a one-time purchase, and Pro unlocks unlimited history.