Conversation
There was a problem hiding this comment.
Pull request overview
Enables sending to Stellar federation addresses (user*domain) by preserving the original federation address for display while using the resolved G... public key for transaction building.
Changes:
- Added
federationAddressto the transaction settings store and propagated it through send flow screens for display and recents. - Updated send UI (amount/review/processing) to show federation address when available.
- Added a new E2E flow to validate federation address send on mainnet and added input search debounce.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ducks/transactionSettings.ts | Adds federationAddress state + setter to track original federation address separately from resolved recipient key. |
| src/components/screens/SendScreen/screens/TransactionProcessingScreen.tsx | Uses federation address (when present) when saving “recent addresses” after a send completes. |
| src/components/screens/SendScreen/screens/TransactionAmountScreen.tsx | Displays federation address in the recipient row when present. |
| src/components/screens/SendScreen/components/SendReviewBottomSheet.tsx | Displays federation address + resolved/truncated G... key in the review sheet. |
| src/components/screens/SendScreen/SendSearchContacts.tsx | Adds debounced search; attempts to store resolved address for transactions while keeping federation for display. |
| e2e/flows/transactions/SendFederatedAddress.yaml | Adds an E2E flow covering federation resolution and a complete send. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * @param {string} address - The recipient address | ||
| * @param {string} address - The recipient address (resolved G... public key) | ||
| */ | ||
| saveRecipientAddress: (address) => set({ recipientAddress: address }), |
There was a problem hiding this comment.
saveRecipientAddress updates recipientAddress but leaves federationAddress untouched. This can lead to stale federation UI (and recent address saving) when other entry points set the recipient without also clearing federation (e.g., TransactionAmountScreen clears recipient on mount but not federation). Consider clearing federationAddress inside saveRecipientAddress (or providing a single setter that updates both) so state can’t become inconsistent.
| saveRecipientAddress: (address) => set({ recipientAddress: address }), | |
| saveRecipientAddress: (address) => | |
| set({ recipientAddress: address, federationAddress: "" }), |
| * @property {Function} saveRecipientAddress - Function to save the recipient address | ||
| * @property {Function} saveFederationAddress - Function to save the federation address | ||
| * @property {Function} saveSelectedTokenId - Function to save the selected token ID | ||
| * @property {Function} saveSelectedCollectibleDetails - Function to save the selected collectilbe details |
There was a problem hiding this comment.
There’s a typo in this JSDoc property description: “collectilbe” should be “collectible”.
| * @property {Function} saveSelectedCollectibleDetails - Function to save the selected collectilbe details | |
| * @property {Function} saveSelectedCollectibleDetails - Function to save the selected collectible details |
| } else if (transactionHash) { | ||
| setStatus(TransactionStatus.SENT); | ||
| addRecentAddress(recipientAddress); | ||
| addRecentAddress(federationAddress || recipientAddress); | ||
| } else if (isContractAddress && !isSubmitting) { |
There was a problem hiding this comment.
Saving federationAddress into recents will break re-sending from the Recent list: loadRecentAddresses persists only the raw string, and selecting a recent federated address currently bypasses searchAddress/federation resolution, so the transaction flow can end up with an unresolved user*domain in recipientAddress. Consider storing the resolved G... address in recents (optionally alongside the federation address for display), or ensure selecting a recent federated address triggers resolution before continuing.
| (text: string) => { | ||
| setAddress(text); | ||
| // eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
| searchAddress(text); | ||
|
|
||
| if (searchDebounceRef.current) { | ||
| clearTimeout(searchDebounceRef.current); | ||
| } | ||
|
|
There was a problem hiding this comment.
With the new debounce, the send recipient store state isn’t cleared until the delayed searchAddress(text) runs. That means searchError / isValidDestination from a previous search can remain visible for ~300ms while the user is typing. Consider clearing the relevant send-recipient state immediately on input change (e.g., add an action like clearSearchState() / setSearching(true) and call it here) so the UI reflects the new input right away.
| const { destinationAddress: resolvedAddress } = | ||
| useSendRecipientStore.getState(); | ||
|
|
||
| const isFederation = isFederationAddress(contactAddress); | ||
| const addressForTransaction = |
There was a problem hiding this comment.
handleContactPress relies on useSendRecipientStore.getState().destinationAddress as the “resolved” address for federation sends. On this screen you call resetSendRecipient() on mount, so destinationAddress will be empty when selecting a recent federated address; the code will then fall back to the raw user*domain and store it as the transaction recipient (breaking transaction building). Instead, when contactAddress is a federation address, resolve it (via searchAddress or direct federation resolve) before calling setDestinationAddress/saveRecipientAddress.
| isSingleRow | ||
| onPress={navigateToSelectContactScreen} | ||
| address={recipientAddress} | ||
| name={federationAddress || undefined} |
There was a problem hiding this comment.
name={federationAddress} makes the Amount screen display dependent on a global store value that may be stale when recipientAddress is set from other entry points (e.g., route params / QR scan) that don’t also set/clear federationAddress. Consider explicitly clearing federationAddress whenever the recipient is reset/overwritten (or derive the displayed federation name from the send-recipient store for the currently selected destination) to avoid showing the wrong federation label for a new recipient.
| name={federationAddress || undefined} |
Untitled.mp4
Checklist
PR structure
Testing
Release