Skip to content

Exchange virtual iban - #1797

Closed
mocodesmo wants to merge 13 commits into
developfrom
exchange-virtual-iban
Closed

Exchange virtual iban#1797
mocodesmo wants to merge 13 commits into
developfrom
exchange-virtual-iban

Conversation

@mocodesmo

Copy link
Copy Markdown
Contributor

This branch introduces a new "Confidential SEPA" (Virtual IBAN) feature that enables private EUR deposits and withdrawals through a personal virtual IBAN. The feature is integrated across funding, withdrawal, and recipient management flows.


1. New Feature: Confidential SEPA / Virtual IBAN

Intro/Activation Screen (VirtualIbanIntroScreen)

  • Shield icon with title "Confidential SEPA" + "NEW" badge
  • Feature description: "Receive a personal virtual IBAN for private EUR deposits and withdrawals"
  • Key Features card with bullet points:
    • "Your own personal virtual IBAN"
    • "Private transfers - your bank only sees your name"
    • "Instant activation - start using immediately"
  • Warning card (yellow/amber) with important notice:
    • "The name on your bank transfers must exactly match your Bull Bitcoin account name"
    • Includes "Contact support now" link to Telegram
  • Account Owner Name field (disabled/read-only) showing user's legal name
  • Checkbox confirmation: "I confirm this is my legal name as it appears on my bank account"
  • "Activate Confidential SEPA" button (disabled until checkbox is checked)

Pending/Activation Screen (VirtualIbanPendingScreen)

  • Schedule/clock icon in a circle avatar
  • Title: "Activating Confidential SEPA"
  • Description: "Creating your personal virtual IBAN. This may take a few minutes."
  • Linear progress indicator (indeterminate)
  • "Use Regular SEPA Instead" button - outlined secondary button for fallback

Activated/Success Screen (VirtualIbanActiveScreen)

  • Checkmark icon (green success color)
  • Title: "Confidential SEPA Activated"
  • Context-aware description based on entry point:
    • Funding: "Your personal virtual IBAN is ready. You can now deposit EUR privately."
    • Sell: "Your personal virtual IBAN is ready. You can now receive EUR payouts privately."
    • Withdraw: "Your personal virtual IBAN is ready. You can now withdraw EUR privately."
  • "Show Virtual IBAN Details" button - navigates to details screen
  • "Continue" button - proceeds with the current flow

IBAN Details Screen (VirtualIbanDetailsScreen)

  • Title: "Privacy Banking" with "NEW" badge
  • Warning card (amber): "Transfers must be sent from a bank account in your name. Mismatched names will be rejected." + "Contact support now" link
  • Copyable detail fields with copy icons:
    • Virtual IBAN Account Number
    • Recipient Name (user's full name)
    • Recipient Address (if available)
    • Bank Account Country (e.g., "France")
    • Bank Address
    • BIC Code
  • Each field shows a copy icon that copies to clipboard with snackbar confirmation

2. Fund Exchange Methods Updates

Europe Funding Methods (FundExchangeEuropeMethods)

  • Added Confidential SEPA option (only for fully KYC-verified users)
  • New list tile with:
    • "Confidential SEPA" title + "NEW" badge
    • Subtitle: "Private deposits to your personal IBAN"
    • Arrow icon for navigation
  • Tapping navigates to the Virtual IBAN flow screen

3. Recipient Management Updates

New Step-Based Flow

The recipient selection flow now uses a step-based navigation for sell/withdraw:

Step 1: Type Selection (RecipientTypeSelectionStep)

  • Country dropdown (locked for withdraw flows)
  • Payout Method radio buttons:
    • "Regular SEPA" (cjPayee)
    • "Confidential SEPA" (frPayee) - shown with:
      • "NEW" badge when VIBAN is not yet activated
      • Subtitle: "Private SEPA transfers using your personal virtual IBAN"
      • Dynamic label: "Activate Confidential SEPA" vs "Confidential SEPA" based on status
  • "Continue" button to proceed

Step 2 (if frPayee selected without VIBAN): Virtual IBAN Activation (VirtualIbanActivationStep)

  • Embedded version of the intro/activation screens
  • Shows intro → pending → activated states
  • "Use Regular SEPA Instead" button always available as fallback
  • Back navigation returns to type selection

Step 3: Enter Details (standard recipient form)

  • Shows the selected type as a header
  • Direct form entry without type selector (type was pre-selected)

Recipients Screen Updates (RecipientsScreen)

  • Now handles step-based flows for sell/withdraw locations
  • Back button on Step 2/3 returns to previous step
  • Segmented tabs: "New Recipient" / "My Recipients"

New Recipient Tab Updates (NewRecipientTab)

  • Step 2 mode: Shows only the form (type already selected in Step 1)
  • Standard mode: Shows jurisdiction dropdown + type selector + form
  • New type labels: "Confidential SEPA" and "Regular SEPA"

Recipient Type Selector Updates (RecipientTypeSelector)

  • Filters out system-managed types (frVirtualAccount)
  • Shows "NEW" badge for frPayee when VIBAN is not active
  • Dynamic label: "Activate Confidential SEPA" vs "Confidential SEPA"
  • Separate label for cjPayee: "Regular SEPA"

Recipients List Tile Updates

  • Extended IBAN display support for new types: frVirtualAccount, frPayee, cjPayee

4. Withdrawal Flow Updates

Amount Screen (WithdrawAmountScreen)

  • New "Use Confidential SEPA" checkbox for EUR withdrawals:
    • Only shown when user has an active Virtual IBAN
    • Title: "Use Confidential SEPA"
    • Subtitle: "Withdraw through your personal virtual IBAN for enhanced privacy"
    • Styled with a container border and background

Confirmation Screen Updates

  • Extended support for new recipient types (frVirtualAccount, frPayee, cjPayee)
  • All show IBAN as the account identifier

5. Payment Screen Updates (PaySendPaymentScreen)

  • Added new recipient type labels in the confirmation view:
    • frPayee: "Confidential SEPA"
    • cjPayee: "Regular SEPA"
    • frVirtualAccount: "Virtual IBAN"

6. Localization Additions

New strings added for multiple languages (EN as primary):

Key Text
confidentialSepaTitle "Confidential SEPA"
confidentialSepaDescription "Receive a personal virtual IBAN for private EUR deposits and withdrawals"
confidentialSepaBullet1-3 Feature bullet points
confidentialSepaWarningTitle "Important"
confidentialSepaWarningDesc Name matching warning
accountOwnerName "Account Owner Name"
confirmLegalName Checkbox confirmation text
activateConfidentialSepa "Activate Confidential SEPA"
activatingConfidentialSepaTitle/Desc Pending state texts
useRegularSepaInstead "Use Regular SEPA Instead"
confidentialSepaActivatedTitle "Confidential SEPA Activated"
confidentialSepaActivated*Desc Context-aware success descriptions
showVirtualIbanDetails "Show Virtual IBAN Details"
privacyBankingTitle "Privacy Banking"
virtualIbanNameWarning Name matching warning for details
virtualIbanAccountNumber "Virtual IBAN Account Number"
recipientName/Address Field labels
bankAccountCountry/bankAddress/bicCode Bank detail labels
newBadge "NEW"
useVirtualIban "Use Confidential SEPA"
useVirtualIbanSubtitle Checkbox subtitle
regularSepa "Regular SEPA"
confidentialSepaShortDesc Short feature description

Visual Design Patterns Used

  1. "NEW" Badge: Tertiary container background, secondary text color, bold small label
  2. Warning Cards: Tertiary/warning container with warning amber icon
  3. Success State: Green check circle icon
  4. Pending State: Schedule/hourglass icon with linear progress
  5. Copyable Fields: ListTile with trailing copy icon, snackbar feedback
  6. Radio Selection: Custom styled radio tiles with border, selection highlight
  7. Fallback Buttons: Outlined secondary style for alternative actions

- Introduced Virtual IBAN functionality for private EUR deposits and withdrawals.
- Updated locator and repository to include Virtual IBAN components.
- Added UI elements and localization for Confidential SEPA.
- Implemented handling for special recipient types related to Virtual IBAN.
- Enhanced funding methods to support Confidential SEPA transactions.
- Consolidated parameter definitions in the Bullbitcoin API datasource for improved readability.
- Removed unnecessary line breaks in various files to enhance code clarity.
- Ensured consistent formatting across multiple components related to Virtual IBAN functionality.
…ams and improve response handling; adjust FundExchangeEuropeMethods layout for KYC verification
…I updates; streamline FundExchangeEuropeMethods layout and remove unnecessary comments
…recipient management with address handling and UI improvements; update localization for new features
…line recipient type handling and enhance location eligibility checks
…g; enhance UI styling and fix activation flow

- Update withdrawal order creation to safely parse nested error responses and extract API error messages
- Fix FR_PAYEE recipient creation to use nested params structure and parse element from response
- Improve Virtual IBAN activation flow by triggering creation on pending state initialization
- Allow create requests from both notSubmitted and pending states for better retry handling
- Update
…rove recipient type selection and navigation logic

- Replace unsupported Virtual IBAN error handling with SEPA transfer designation in pay and send payment screens
- Adjust recipient type selection logic to enhance user experience and streamline flow
- Refine step-based navigation checks for recipients location
- Improve state management in withdraw flow to accommodate user navigation
…g in payment screens

- Refactor recipient type selection logic to enhance clarity and maintainability
- Improve formatting and alignment of UI elements in pay_receive_payment_screen and pay_send_payment_screen
- Update error handling for unsupported Virtual IBAN types to ensure consistent user experience
@mocodesmo
mocodesmo requested review from ethicnology, i5hi and kumulynja and removed request for i5hi January 20, 2026 20:56
@mocodesmo

Copy link
Copy Markdown
Contributor Author

@kumulynja this feature required comprehensive updates to recipients . please check if it's structured correctly


/// Entity representing a user's physical address.
@freezed
sealed class UserAddress with _$UserAddress {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not an entity since it has no identity, no business rules or whatever makes something an entity. It also has protocol level things like from/to json which should only be present in models in the adapters, not in the domain. The same for address stringified it is also not something to put in an entity or in the domain in general if it is not used in the domain. It feels more like a presentation concern and as far as I can see the UI is indeed the only place where it is used, so shouldn't be here but there.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, the UserAddress concept and so class can be in the domain of course, but get it out of the entity folder and remove the json and stringied stuff. This is more of a Value Object, since it is used as a field in the virtual iban recipient entity. It is not an entity itself.

_apiKeyDatasource = apiKeyDatasource,
_isTestnet = isTestnet;

Future<String> _getApiKey() async {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the frameworks/http folder in recipients feature and reuse that way of managing the api key.
(Best would be to move that http folder to core actually to reuse it for all exchange features instead of repeating in every feature)

/// - Only show recipients with isOwner=true
/// - Group by IBAN
/// - If both cjPayee and frPayee exist for the same IBAN, keep only frPayee
class FilterRecipientsByVirtualIbanUsecase {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be a usecase. This acts on View Models and doesn't use any ports/adapters, this should just be done in the Presentation layer (bloc state probably), not in a usecase.

@@ -0,0 +1,12 @@
/// Defines the current step in the recipient selection flow.
/// Used for multi-step flows like sell/withdraw where VIBAN activation may be required.
enum RecipientFlowStep {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a domain thing. This is for navigation. This should not be here.

);

// For step-based flows (sell, withdraw, pay), handle step-based navigation
if (location.usesStepBasedFlow) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this step based flow like this needs another thought to see if there are no better ways like nested navigation. This feels hacky and error-prone and it now mixes three different ways of some sort of navigation, go router, tabs and now steps in the tabs. This is just a first impression, I should look at it some more, but first though is there should be a better way.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you think of or try using StatefulShellRoute navigation to be able to have steps in tabs?

on<RecipientsCadBillersSearched>(_onCadBillersSearched);
on<RecipientsSelected>(_onSelected);
// Virtual IBAN step flow navigation handlers
on<RecipientsNextStepPressed>(_onNextStepPressed);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This confirms my first impression that the step based stuff is not good. This mixes navigation into the BLoC, no bueno. The BLoC is the controller to invoke and pass data to and from the usecases, not for navigation logic.

class VirtualIbanRouter {
/// Creates a shell route that provides the singleton VirtualIbanBloc.
/// No location parameter needed - the bloc is a singleton that's already loaded.
static ShellRoute createRoute() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We stopped using ShellRoute since it affects default/native back navigation. Better to just pass the BLoC as extra in the navigation routes to use the same instance for different routes and don't lose the default back navigation when entering a flow/feature's first route.

…across exchange features

- Introduced BullbitcoinApiKeyProvider to streamline API key retrieval and management.
- Updated VirtualIbanRepository to utilize the new provider instead of the deprecated BullbitcoinApiKeyDatasource.
- Refactored ExchangeLocator and RecipientsLocator to register and reuse the API key provider.
- Changed imports from user_address entity to value_objects for consistency and clarity.
- Removed unused recipient-related classes and methods to clean up the codebase.
@mocodesmo

Copy link
Copy Markdown
Contributor Author

@kumulynja the following changes were made
Summary of PR Review Changes
Implemented (Comments 1-4)

  1. UserAddress: Entity → Value Object ✅
    Moved from domain/entity/ to domain/value_objects/
    Removed addressStringified from domain - now lives as _formatAddressForDisplay() helper in virtual_iban_details_screen.dart (UI layer)
    JSON serialization kept for freezed compatibility with UserSummary.fromJson
  2. HTTP Pattern to Core ✅
    Moved frameworks/http/ from features/recipients/ to core/exchange/
    BullbitcoinApiKeyProvider now registered once in ExchangeLocator and shared
    Updated VirtualIbanRepositoryImpl to use BullbitcoinApiKeyProvider instead of BullbitcoinApiKeyDatasource
    Recipients feature now imports from core
  3. FilterRecipientsByVirtualIbanUsecase → Presentation ✅
    Deleted the usecase file entirely
    Inlined filtering logic as _filterForVirtualIban() private method in RecipientsState
    Logic operates on RecipientViewModel (presentation), so correctly lives in presentation layer
  4. RecipientFlowStep: Domain → Presentation ✅
    Moved from domain/value_objects/ to interface_adapters/presenters/models/
    This is navigation/UI state, not a domain concept

Pending discussion

Deferred (Comments 5-7) - Navigation Architecture
Comment 5: Step-based flow in recipients_screen.dart mixing go_router, tabs, and steps
Comment 6: Navigation logic in recipients_bloc.dart (step handlers) should not be in BLoC
Comment 7: ShellRoute in virtual_iban_router.dart affecting native back navigation
You suggested considering StatefulShellRoute or passing BLoC via route extras (like withdraw, pay, swap do). These require deeper architectural discussion before implementation.

@mocodesmo
mocodesmo force-pushed the exchange-virtual-iban branch from 47d3ede to 7e26795 Compare January 21, 2026 15:28
@mocodesmo mocodesmo closed this Mar 25, 2026
@thibistaken
thibistaken deleted the exchange-virtual-iban branch May 13, 2026 13:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants