Conversation
There was a problem hiding this comment.
Pull request overview
Adds Testnet Soran name resolution to payment flows and transaction history, including route validation, local annotations, and localization.
Changes:
- Resolves and validates Soran destinations, memos, muxed accounts, and contracts.
- Displays current and historically used names in account and asset history.
- Adds secure storage messaging and comprehensive regression tests.
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
extension/src/popup/views/AccountHistory/hooks/useGetHistoryData.tsx |
Adds naming metadata and muxed senders. |
extension/src/popup/views/AccountHistory/hooks/__tests__/useGetHistoryData.test.tsx |
Tests history naming metadata. |
extension/src/popup/views/__tests__/Account.test.tsx |
Updates localized date expectation. |
extension/src/popup/locales/pt/translation.json |
Adds Portuguese Soran strings. |
extension/src/popup/locales/en/translation.json |
Adds English Soran strings. |
extension/src/popup/hooks/useSoranHistoryName.ts |
Loads current and saved names. |
extension/src/popup/hooks/__tests__/useSoranHistoryName.test.tsx |
Tests history-name loading. |
extension/src/popup/helpers/soranTransaction.ts |
Validates Soran transaction routes. |
extension/src/popup/helpers/soranPrimary.ts |
Implements batched Primary-name reads. |
extension/src/popup/helpers/soranHistory.ts |
Selects counterparties and formats timestamps. |
extension/src/popup/helpers/soran.ts |
Implements Soran lookup and decoding. |
extension/src/popup/helpers/__tests__/soranTransaction.test.ts |
Tests transaction validation. |
extension/src/popup/helpers/__tests__/soranPrimary.test.ts |
Tests Primary-name reads and caching. |
extension/src/popup/helpers/__tests__/soranHistory.test.ts |
Tests history helpers. |
extension/src/popup/helpers/__tests__/soranAdversary.test.tsx |
Tests adversarial signing and access cases. |
extension/src/popup/helpers/__tests__/soran.test.ts |
Tests name resolution and ABI decoding. |
extension/src/popup/helpers/__tests__/fixtures/soran-destinations.json |
Adds Soran ABI vectors. |
extension/src/popup/components/sendCollectible/SelectedCollectible/hooks/useSimulateTxData.ts |
Validates collectible routes. |
extension/src/popup/components/send/SendTo/index.tsx |
Integrates names into recipient selection. |
extension/src/popup/components/send/SendTo/hooks/useSendToData.tsx |
Resolves names and prevents stale results. |
extension/src/popup/components/send/SendTo/hooks/__tests__/useSendToData.soran.test.tsx |
Tests recipient resolution. |
extension/src/popup/components/send/SendAmount/index.tsx |
Locks Soran-provided memos. |
extension/src/popup/components/send/SendAmount/hooks/useSimulateTxData.tsx |
Revalidates simulated transfers. |
extension/src/popup/components/InternalTransaction/SubmitTransaction/hooks/useSubmitTxData.tsx |
Revalidates submission and saves names. |
extension/src/popup/components/InternalTransaction/SubmitTransaction/hooks/__tests__/useSubmitTxData.telemetry.test.tsx |
Tests submission revalidation and annotations. |
extension/src/popup/components/hardwareConnect/HardwareSign/index.tsx |
Validates before hardware signing. |
extension/src/popup/components/hardwareConnect/HardwareSign/__tests__/HardwareSign.test.tsx |
Tests hardware validation. |
extension/src/popup/components/accountHistory/TransactionDetail/styles.scss |
Styles name details. |
extension/src/popup/components/accountHistory/TransactionDetail/index.tsx |
Displays names and revised timestamps. |
extension/src/popup/components/accountHistory/HistoryItem/styles.scss |
Styles history-row names. |
extension/src/popup/components/accountHistory/HistoryItem/index.tsx |
Displays names in history rows. |
extension/src/popup/components/__tests__/SoranHistoryDisplay.test.tsx |
Tests name presentation. |
extension/src/constants/localStorageTypes.ts |
Adds the annotation storage key. |
extension/src/background/messageListener/popupMessageListener.ts |
Routes protected annotation messages. |
extension/src/background/messageListener/handlers/soranPaymentNames.ts |
Stores and retrieves annotations. |
extension/src/background/messageListener/handlers/__tests__/soranPaymentNames.test.ts |
Tests annotation storage. |
extension/e2e-tests/accountHistory.test.ts |
Updates address selectors. |
@shared/constants/services.ts |
Adds Soran service types. |
@shared/api/types/types.ts |
Types muxed senders. |
@shared/api/types/soran.ts |
Defines annotation references and keys. |
@shared/api/types/message-request.ts |
Defines annotation messages. |
@shared/api/internal.ts |
Adds annotation API wrappers. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| export const formatHistoryTimestamp = (createdAt: string, locale?: string) => { | ||
| const date = new Date(createdAt); | ||
| if (Number.isNaN(date.getTime())) return "—"; | ||
| return `${date.toLocaleDateString(locale, { year: "numeric", month: "short", day: "numeric" })} • ${date.toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" })}`; |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 42 out of 42 changed files in this pull request and generated 2 comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
extension/src/popup/helpers/soranHistory.ts:42
- The new formatter still follows the locale's default hour cycle, so locales such as
en-USrender9:58 AMrather than the promised 24-hour time. Set an explicit 24-hour cycle; the current test only checks that the output is valid and therefore misses this regression.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 43 out of 43 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
extension/src/popup/helpers/soranHistory.ts:22
- Token-transfer rows fall through when Horizon omits
asset_balance_changes.getRowDataByOpTypestill recognizes those rows viaattrs.amount, and already computesisReceivingplusattrs.from/actualDestination, but its metadata only setsisTokenTransferandto; because this condition does not includeisTokenTransfer, no Soran name is shown for that supported fallback path. PreservefromandisReceivingin the token-transfer metadata and handleisTokenTransferhere as well.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 43 out of 43 changed files in this pull request and generated no new comments.
Suppressed comments (3)
Previously missed (1) — in code that hasn't changed since the last review.
extension/src/popup/helpers/soranTransaction.ts:47
- Contract token symbols may contain
:, but splitting at the first colon treats part of the symbol as the issuer. A valid Soran transfer for a token such asfoo:bar:<contract>therefore computes an invalid expected contract and is rejected. Parse the canonical ID at its last colon (assplitCanonicaldoes elsewhere).
This issue also appears on line 117 of the same file.
extension/src/popup/helpers/soranTransaction.ts:119
- This contract-asset guard also parses the first colon, so a contract token whose symbol contains
:is misclassified as a classic asset. An altered classic payment to the same recipient could then pass route validation instead of being rejected. Inspect the issuer after the final colon.
extension/src/popup/helpers/soranHistory.ts:43 - The PR specifies a 24-hour clock, but
toLocaleTimeStringdefaults to the locale's hour cycle; for example,en-USrenders09:58 AM. Explicitly disable the 12-hour cycle so the timestamp meets that requirement in every supported locale.
|
The amount-precision finding is fixed in e1d83a0. Soran token payments now carry exact base-unit decimal strings into locally constructed For the mux-capability finding, the described failure does not occur in the current implementation: Validation: 2,274 unit tests across 244 suites passed, including 15 additional cases. Tests now decode the actual outgoing simulation XDR rather than only mocking a prepared response. They cover amounts above JavaScript’s safe-integer limit, the The earlier audit fixes in 0062587 remain in place: stale simulation/review invalidation, displayed-fee consistency, Soran path-payment validation, collectible ID The timestamp change continues to preserve each locale’s preferred hour cycle and requested regional language tag. Tests cover |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 43 out of 43 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
extension/src/popup/helpers/soranHistory.ts:43
- This still follows each locale’s default hour cycle, so
en-USrenders values such as09:58 AM; it does not implement the PR’s stated 24-hour clock behavior. Explicitly request the 24-hour cycle.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 43 out of 43 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
extension/src/popup/components/accountHistory/TransactionDetail/index.tsx:342
- Use the detected locale rather than
resolvedLanguagehere. This repository only providesenandptresource bundles, so i18next resolves anen-GBbrowser to theenbundle; passing that value toIntlloses the region and can select the 12-hour English default, contrary to the intendeden-GB24-hour display.i18n.languageretains the detected regional tag while translations can still fall back normally.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 44 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
extension/src/popup/views/AccountHistory/hooks/useGetHistoryData.tsx:943
- Valid collectible token ID
0never reaches this new naming metadata: the precedingif (!attrs.tokenId)returns the generic row for zero, even though the parser represents ascvU32(0)astokenId: 0. As a result, token #0 transfers still cannot show sender/current-name information. Treat onlynull/undefinedas missing (and add a zero-ID regression case).
Freighter can resolve Soran names when sending payments and display names in account and asset history on Stellar Testnet.
What is Soran?
Soran is a naming system built on Stellar's Soroban smart contracts. Names use the format
username.namespace, such asalice.novaorrobert.orange. The same Universal Lookup contract serves supported namespaces;.novais an example, not a restriction.This integration reads Universal Lookup through unsigned Soroban RPC simulation. It does not use Soran's HTTP API or submit transactions for lookups. See the documentation and on-chain resolution reference.
Changes
G...), accounts with ID/text/hash memos, muxed accounts (M...) and contract destinations (C...) in supported transfer flows. Preserve required memos and muxed IDs, retain the name through review and recents, and revalidate before sending.i128transaction XDR before simulation, avoiding numeric JSON rounding. Reuse Freighter’s existing transaction-simulation endpoint without changing its backend schema. Validate destinations, memos, operation types, contract IDs, exact token amounts and displayed simulation fees before accepting prepared transactions. Reject unsupported routing, excess precision, nonpositive amounts and overflow. Before software/hardware signing and submission, require the full transaction body to match the reviewed transaction; only signatures may change. Apply these checks to Soran path payments as well as direct payments. Use the sharedsplitCanonicalhelper for token symbols containing:.primary_namescalls with bounded caching and a 20-second HTTP timeout. Retain the correct counterparty and direction for token, collectible (including ID0) and account-creation history, including transfers without asset balance changes. Omit names when direction is unavailable.undefinedhistory timestamp suffix while retaining each locale's preferred hour cycle and requested regional language tag (en-GB,en-US,pt-BR).Testnet examples
Switch Freighter to Testnet and use a funded test wallet whose address differs from the recipient. In Send → XLM, enter one of these names and continue to review. Confirm the exact destination and routing information below; memo-bearing names must populate and lock the memo. Looking up a name does not send funds.
orange.orangeGAOHJ6KE5XUQCKXBANQ4JLHZLQ25727DBJDU7PEEZ77OAJVTA2DC3XMMmux.novaMDHHA2WBSH4ZKIAWALPY4KVOC57ZUT6W6HWS3JBUQ4KFJRT6US4MWAAAAAAAAAAAFKV2W42; no transaction memorobert.orangeGDRECIBHDKSB2X72Z7TPSU4BKABFV5ALFAD57X57YBOBCWYOZ2B2AVEC77alice.novaGBES5UHJYI445RV4XBGWHZOMBW4RYXBHOX47ZNZAJZAH2WP42ZEP2DYQhelloFor
mux.nova, the completeM...address must be retained; its base account isGDHHA2WBSH4ZKIAWALPY4KVOC57ZUT6W6HWS3JBUQ4KFJRT6US4MXTZ5and its routing ID is42. The ID is not a transaction memo. An unsupported flow must reject the transfer rather than replace the M address with its base G account.Expected history display: the current Primary names are
mux.nova,robert.orangeandalice.novafor their corresponding destinations.orange.orangecurrently returns no Primary name, so history without a saved payment-name annotation falls back to the address. After a successful send through this integration, Freighter saves and displaysSent using <name>separately from the current Primary name. For G-plus-memo routes, a Primary name identifies the account, not a particular memo-routed customer.These results were verified through read-only Universal Lookup calls on 12 September 2026 at 16:11 UTC (destination ledger 4,641,182; Primary ledger 4,641,183). Testnet records can change; these are observed results, not permanent fixtures.
Testnet contracts
CDSORANQAJK35UV2HR63CMB6M5NYISHMUBTB6EQY2CZ3Y7HJDIOHRJWA. Freighter callsresolve_destinationfor payments andprimary_namesfor history, with Registry and ABI compatibility checks.CCSORANDPQINYOYB5SVO45WJP2LBBYKC72HHUIRVXB4J6RUZKDAUW7G4. Freighter verifies this anchor through Lookup'sregistry(). Lookup discovers each namespace's current Registrar and Resolver; no Nova-specific contracts are hardcoded.CCSORAN7Y7ICQK2MBSVCJT3BUN5EHXKDKSTMGVB6QWSYXWMMLG2WIFJ6. The documented shared G/C election contract, accessed through Lookup rather than called or hardcoded directly by Freighter. Muxed elections are handled by Lookup for the complete account-plus-ID identity.Addresses: Soran's shared Testnet deployment. Other networks are currently rejected. Contract reads trust the selected RPC and configured deployment; Wasm hashes are not pinned.
Validation
alice.nova, changing 1→2 XLM and reviewing again retained the lockedhellomemo. No payments were submitted in this retest.9007199254740993, thei128maximum, G/M/C destinations, rejected altered responses, numeric/custom-network compatibility, and ordinary-address fallback after capability lookup failures. Read-only Testnet checks through the existing simulation endpoint passed for G/M destinations with exact amounts and consistent fees; no transactions were signed or submitted.adam.novaretained memo12345and the original payment name, while the return payment displayed the account’s elected Primary name,general.nova.Demonstration
Freightersorandemo.mov