Skip to content

Onboarding Guide: The Journey of a Transaction

Page Info

What: End-to-end walkthrough of three core scenarios — FPS deposit, eDDA deposit, and BST withdrawal — connecting all knowledge points across this manual Audience: Product managers who are new to the deposit/withdrawal business and need to build a holistic understanding quickly Prerequisites: None — this is the starting point Reading time: 8 minutes Owner: Deposit & Withdrawal Product Team

Key takeaway: Three core scenarios connect all knowledge points — FPS deposit follows the Push matching path, eDDA deposit follows the Pull direct debit path, and BST withdrawal follows the auto-approval + bank-securities transfer path. Understanding these three paths gives you a complete picture of the system.


30-Second Overview

User initiates request → Bank statement/instruction exchange → Auto matching/approval → Funds credited/remitted → Reconciliation

The deposit and withdrawal system is moomoo's fund channel layer — the bridge connecting user bank accounts to securities accounts.

DimensionCountDescription
Deposit Methods10BST, FPS, eDDA (HASE/HSBC), Internet Banking, ATM, Cheque, Bill Payment, Overseas, Airstar
Withdrawal Channels12BST, BOCHK B2E/FPS, HASE/HSBC Internet Banking, SCB/CGB FPS, CHATS, Wire, Cheque
Supported Banks16BOCHK, HSBC, HASE, ICBC, SCB, CGB, CMB, MS, Airstar, EWB, etc.
Currencies5HKD, USD, CNH, JPY, SGD
BoundarySystem ResponsibilityNot System Responsibility
EntryReceive user deposit/withdrawal requestsUser registration, KYC, account opening
Bank IntegrationStatement parsing, remittance instructions, eDDA/eDDIBank internal processing, SWIFT intermediation
Fund OperationsCreate SBA procedures to operate ledgerLedger balance management itself (SBA's responsibility)
Risk ControlInvoke blacklist/whitelist, high-risk checksRisk control rule engine itself
NotificationsTrigger deposit/withdrawal result notificationsPush channel management

Deposit and Withdrawal are two completely independent services — the deposit core is "matching" (money arrived, identify whose it is), while the withdrawal core is "approval" (money is leaving, can it be released).


Choose Your Reading Path by Role

Different roles focus on different areas. First read the three scenarios below to build holistic understanding, then dive deeper based on your role:

Product Manager: Understand business rules + know what to change

Core path: Deposit Methods OverviewMatching & Auto-depositWithdrawal Rules ManualBank Capability Matrix

Key focus: The If requirements change collapsible block at the bottom of each page — telling you "what code needs to change if this feature changes"

Quick Reference: Deposit Rules Reference · Withdrawal Data Dictionary · Refunds & Reversals · FAQ

Operations Staff: Master procedures + handle exceptions

Core path: Manual Matching GuideWithdrawal Approval GuideReversal/Refund GuideScheduled Tasks & Monitoring

Key focus: CRM navigation paths, field mapping tables, decision flow diagrams, SLA timelines

Troubleshooting: Deposit Troubleshooting · Withdrawal Troubleshooting

Developers: Understand system architecture + locate code

Core path: System Architecture & Data FlowSBA Fund OrchestrationBank Cards & Authorization

Key focus: Code location annotations in each page (file paths in the If requirements change collapsible blocks)

Bank Integration: BST · HSBC · Hang Seng · BOCHK


Below we walk through three real scenarios covering every step of deposit and withdrawal. FPS and eDDA are two fundamentally different deposit models — the former is user-initiated transfer (Push), the latter is system-initiated debit from the user's bank account (Pull). Understanding this distinction is key to understanding the entire deposit system.


Deposit Journey: A HKD 50,000 FPS Deposit

Scenario: User selects "FPS" in the moomoo App to transfer HKD 50,000 to their securities account.

Step 1: User Initiates Application

User taps "Deposit" in the App, selects deposit method fps (method code 3), enters amount 50,000, and selects currency HKD.

The system calls the deposit service's ApplyController.applyAction(), performing the following checks:

CheckDescription
User PermissionsVerify WEB/OA signature, confirm user identity
Deposit RestrictionsCall AccountLockBusiness::isDepositRestricted() to check if the account is restricted from deposits

Once checks pass, an Apply record is created, written to the applys_{uid % 100} sharded table:

FieldValueDescription
status0 (PENDING)User has applied, awaiting matching
deposit_methodfpsFPS
amount50000Applied amount
currencyHKDHong Kong Dollar
export_bank_idUser-selected bankPaying bank (user side)
import_bank_idSystem-assignedReceiving bank (company side)

Learn More

All 10 deposit methods → Deposit Methods Overview Meaning of every Apply table field → Deposit Rules Reference § Core Fields

Step 2: User Completes FPS Transfer

User switches to their banking app and completes the HKD 50,000 transfer via FPS.

FPS is an instant settlement payment system — funds are immediately debited from the user's bank and credited to the company's sub-account at SCB or CGB.

Step 3: Bank Statement Reaches the System

The SCB/CGB FPS gateway pushes the transaction statement to the system. The statement is written to the flows_{bankType}_{YYYYMM} sharded table with key information:

FieldValueDescription
Statement TypeFPS TransferFPS transfer identifier
RemarksFPS...FPS transaction reference number
Amount50000.00Actual received amount
CurrencyHKDHong Kong Dollar

Statement collection methods vary significantly across banks:

BankMethodTimeliness
BOCHKB2E active pull3 times daily + 2-hour conversion
HSBCMT910 real-time pushSeconds
SCB/CGBFPS APIReal-time
CMB/MSBST bidirectional linkEvent-driven, real-time
EWBCSV + BAI2 filesManual upload as needed

Learn More

Complete bank collection frequency table → Architecture & Data Flow Bank FPS capabilities → Bank Capability Matrix

Step 4: Automatic Matching Engine Starts

The matching engine is a set of scheduled tasks, one per bank, running every 3 minutes (e.g., php artisan match:boc).

The engine takes all unprocessed statements with status = PROCESSING and pending applications with status = PENDING, then performs five-dimensional comparison:

DimensionMatch FieldMatch Logic
1. CurrencycurrencyMust match exactly
2. AmountamountMatch within tolerance (HKD/CNH/JPY: 0~20 difference; USD/SGD: 0~3 difference)
3. Nameen_name / cn_nameExact or fuzzy match
4. DatedateWithin ±15 days of application date
5. Card Numberbank_card_numberBank account number match

Three possible match results:

Result CodeMeaningNext Step
2 (RESULT_DEPOSIT)Full match, eligible for auto-deposit→ Proceeds to auto-deposit evaluation
1 (RESULT_NORMAL)Partial match, requires manual confirmation→ Creates match record, awaits operations review
0 (RESULT_NOT)No match→ No action

Our FPS deposit: currency HKD matches, amount 50,000 exact match, name matches, date is today, card number matches → RESULT_DEPOSIT (full match).

Learn More

Complete five-dimensional matching rules and tolerance logic → Automatic Matching Engine What happens when matching fails → Exceptions & Manual Processing

Step 5: Auto-Deposit Evaluation

A successful match does not automatically mean auto-deposit. The system must also check 5 auto-deposit conditions:

#ConditionThis Transaction
1Amount does not exceed currency limitHKD 50,000 < HKD 2,000,000 limit → Pass
2Statement has not been manually rejectedreject == 0 → Pass
3Within the allowed auto-processing time windowDuring business hours → Pass
4One statement maps to only one usercount(uids) == 1 → Pass
5Daily auto-deposit count has not exceeded 10First transaction → Pass

Auto-deposit limits by currency:

CurrencyMax Auto-Deposit Amount
HKD2,000,000
USD300,000
CNH2,000,000
JPY40,000,000
SGD350,000

All 5 conditions pass → System determines this as a NORMAL deposit type.

Learn More

6 deposit orchestration modes → SBA Fund Orchestration Currency limits and status codes → Deposit Rules Reference

Step 6: SBA Orchestration Execution

The system sends a deposit orchestration request to SBA (Server Bank Account), creating a Procedure:

Deposit Procedure (NORMAL mode) execution sequence:
  1. Check freeze →
  2. Credit funds (add to securities account balance) →
  3. Release freeze →
  4. Complete

SBA is the system's "internal bank" — all operations involving fund balance changes are completed through SBA Procedures, ensuring atomicity and consistency.

Learn More

What is SBA → SBA Concepts & Data Model Trigger conditions for 6 deposit orchestration modes → SBA Fund Orchestration

Step 7: Funds Credited, User Receives Notification

Procedure executes successfully, Apply status updates to 2 (DONE).

System sends a push notification (NOTICE_TYPE_NORMAL), and the user sees "Deposit Successful" in the App.

End-to-end time for this FPS deposit: FPS statement arrives in real-time + matching engine 3-minute cycle + SBA execution in seconds ≈ 3–5 minutes.


Deposit Journey II: A HKD 20,000 eDDA Deposit

Scenario: User has already bound their HSBC bank card and completed eDDA authorization. They select "eDDA Electronic Direct Debit" in the moomoo App to deposit HKD 20,000.

Fundamental Difference Between eDDA and FPS

FPS is user-initiated transfer (Push) — the user operates in their banking app, and after funds arrive, the system needs the matching engine to identify "whose money is this". eDDA is system-initiated debit (Pull) — after the user submits in the moomoo App, the system directly debits from the user's bank account. No matching engine needed, because the system initiated the debit itself and inherently knows who the funds belong to.

Step 1: Prerequisite — eDDA Authorization

Before initiating an eDDA deposit, the user must first complete a one-time eDDA authorization, allowing Futu to directly debit from their bank account.

Authorization status is tracked in the setup_eddis table:

Status CodeMeaningDescription
3WAITINGAwaiting authorization initiation
1PENDINGAuthorization in progress, awaiting bank confirmation
2EFFECTAuthorization successful, can deposit
0FAILAuthorization failed

The system checks authorization progress via SetupEddaCheckAuthorizationJob (polling every 600 seconds), with a maximum wait of approximately 10 days (3000 retries).

Common authorization failure reasons:

Error CodeMeaning
MFISAC01Incorrect bank account number
MPP01005~01008ID number/phone number/name mismatch
MPP06001Bank account status abnormal

Learn More

Differences between HSBC eDDA and Hang Seng eDDA → HSBC / Hang Seng Which bank cards support eDDA → eDDA Supported Range (HSBC channel: 15 banks, Hang Seng channel: 12 banks)

Step 2: User Initiates eDDA Deposit

User taps "Deposit" in the App, selects deposit method eddaHSBC (method code 9), and enters amount 20,000 HKD.

After creating the Apply record, the system verifies eDDA authorization status:

Verification logic (verifyEddaBankCard):
  Hang Seng eDDA → Must be pre-authorized (status = EFFECT)
  HSBC eDDA (same bank) → Must be pre-authorized
  HSBC eDDA (cross-bank + online account opening) → Post-authorization allowed

Our scenario: HSBC same-bank, authorization is effective → Verification passes.

Apply record:

FieldValueDifference from FPS
status0 (PENDING)Same
deposit_methodeddaHSBCFPS uses fps
amount20000
currencyHKDSame

Step 3: Async Task Queue Initiates Debit

This is the biggest difference between eDDA and FPS — the user does not need to switch to their banking app.

After the Apply is created, the system automatically triggers a task chain:

ApplyFollowJob (detects method = eddaHSBC)
  → HsbcEddiCreateJob (initiate debit)
    → HsbcEddiResultJob (poll debit result)

HsbcEddiCreateJob calls Eddi::applyHsbcEddi() to build the debit request:

ParameterDescription
debtor_bank_codeUser's bank code (HSBC 3-digit)
debtor_account_identificationUser's bank account number
debtor_nameUser's name
creditor_bank_codeFutu receiving bank code
creditor_account_identificationFutu receiving account number
instructed_amount20000 (debit amount)
instructed_amount_currencyHKD

The system sends the debit instruction to HSBC via the SBA service. It also writes to the hsbc_eddis table, using a unique index on apply_id to prevent duplicate debits.

Learn More

Deposit method comparison → Deposit Methods Overview

Step 4: Bank Executes Debit

After HSBC receives the eDDI (Electronic Direct Debit Instruction):

  1. Verifies user account balance
  2. Debits HKD 20,000 from user's account
  3. Transfers funds to Futu's account at HSBC
  4. Returns execution result via eDDA Report

The hsbc_edda_report service receives HSBC's execution report and updates the Procedure status:

Report StatusMeaningSystem Action
finishedDebit successfulUpdate Apply real_amount, mark as credited
rejectedDebit rejectedRecord reject_reason_code, notify user

Step 5: SBA Credit (Skips Matching Engine!)

Key difference: eDDA deposits completely skip the matching engine.

In the matching service code, eDDA is explicitly excluded:

HsbcMatch matching logic:
  if (deposit_method == 'eddaHSBC') → return no match (skip)

HangSengMatch matching logic:
  if (deposit_method == 'edda') → return no match (skip)

Because the system initiated the debit itself, it inherently knows which user the funds belong to and which application they correspond to — no five-dimensional comparison needed.

After successful debit, SBA directly creates a deposit Procedure to complete the credit.

Step 6: Funds Credited, User Receives Notification

HsbcEddiResultJob polls and detects debit success → Apply status updates to 2 (DONE) → Push notification sent.

End-to-end time from submission to credit: Debit instruction sent in seconds + bank processing typically a few minutes to a few hours (depends on bank processing speed).


FPS vs eDDA: Two Deposit Models Compared

DimensionFPS (Push)eDDA (Pull)
Fund DirectionUser actively transfers inSystem debits from user's account
User ActionMust switch to banking appOne-click within moomoo App
PrerequisitesNoneeDDA authorization required first
Matching EngineFive-dimensional matching requiredCompletely skipped
Credit CertaintyDepends on match resultDebit = confirmation
Supported BanksSCB, CGB, BOCHK, etc.HSBC channel: 15 banks, Hang Seng channel: 12 banks (full list)
User ExperienceMultiple steps, cross-appBest experience, one-click deposit
Data Tablesapplys + flows + matchesapplys + hsbc_eddis/hs_eddis + setup_eddis
Async TasksMatching engine scans periodically (3 min)Job queue actively progresses
Failure HandlingStatement arrived but no match → manualBank rejects debit → notify user

Why is eDDA the core flow?

eDDA achieves the best "one-click deposit within the App" experience — no need to switch banking apps, no waiting for matching. eDDA accounts for approximately 78% of total deposits (HSBC eDDA single channel accounts for 72%, Hang Seng eDDA approximately 6%), making it the dominant method. The HSBC channel supports personal accounts from 15 banks, and the Hang Seng channel supports 12 — it's not limited to HSBC and Hang Seng's own bank cards. Understanding the eDDA authorization-debit-credit chain is key to understanding deposit product design. See eDDA Supported Range.


Withdrawal Journey: A HKD 30,000 BST Withdrawal

Scenario: User initiates a withdrawal in the moomoo App, withdrawing HKD 30,000 to their CMB bank card via the BST channel.

Step 1: User Initiates Withdrawal Request

User taps "Withdraw" in the App, selects their CMB bank card, and enters amount 30,000 HKD.

The system calls the withdrawal service's WithdrawCreator.apply(), performing a series of pre-checks:

CheckDescription
Withdrawal RestrictionsCheck if user is restricted from withdrawals
BlacklistCall hk-withdraw-blacklist-go to check withdrawal blacklist
Risk Control StatusVerify user's risk control status
Currency-Market ConsistencyHKD belongs to HK market, consistent
Available Withdrawal MethodsCheck withdrawal methods supported by user's bank card
FeesCalculate withdrawal fee
Bank Card InfoVerify bank card is valid

Once checks pass, the system executes an atomic transaction, completing in one go:

  1. Create SBA List record
  2. Create Task record (withdrawal task)
  3. Create Apply record
  4. Add Flow operation log

Learn More

Meaning of every withdrawal task field → Withdrawal Data Dictionary § Core Fields All 12 withdrawal channels → Withdrawal Methods Overview

Step 2: Channel Routing — System Selects Withdrawal Method

The system automatically determines the withdrawal channel via calcMethod():

Decision tree:
  1. Does the user's bank card support BST?
     ├─ Yes → CMB (CMBHK) supports BST → method = auto_bs
     └─ No → Continue evaluation
  2. Is the bank in Hong Kong?
     ├─ No → method = tele_transfer (cross-border wire)
     └─ Yes → method = null (requires manual selection)

The CMB bank card supports BST (Bank-Securities Transfer), so the system automatically sets method = auto_bs.

Step 3: Determine Approval Workflow Template

Withdrawal tasks have a three-step approval, but not every transaction goes through all three steps:

StepNameWhen Required
Step 1: AuditHigh-risk reviewOnly for high-risk/OM accounts
Step 2: ConfirmConfirm instructionAll withdrawals
Step 3: RemittanceRemit fundsAll withdrawals

This transaction is not high-risk, so the workflow template is [Confirm, Remittance], skipping Audit.

Step 4: Confirm — Confirm Instruction

Operations staff (or automated system) at the Confirm step:

  1. Verify bank card — Confirm CMB bank card status is normal
  2. Confirm withdrawal methodauto_bs (BST) already auto-set

For the auto_bs channel, the Confirm step does not call SBA startTransfer() (that action is reserved for Remittance).

Action: Click "Submit to Next Step" (NEXT) → Proceeds to Remittance.

Step 5: Remittance — Remit Funds

This is the critical step. For the auto_bs (BST) channel, the system checks auto-withdrawal conditions:

#ConditionDescriptionThis Transaction
1Channel is auto_bsOnly BST channel supports auto-withdrawalYes → Pass
2Not migrated dataExclude historical data migrated from legacy systemNew data → Pass
3Auto-withdrawal switch is ONauto_settings table: corresponding currency status = OPENHKD is ON → Pass
4Amount within limitamount ≤ max_amount30,000 ≤ configured limit → Pass
5Sufficient balanceamount ≤ available_balanceBalance sufficient → Pass
6Daily count not exceededSame user today < 10 transactionsFirst transaction → Pass

All pass → System calls SBA startTransfer() (async), creating a withdrawal Procedure.

Learn More

Complete three-step approval process → Withdrawal Lifecycle Withdrawal channel routing decision tree → Withdrawal Methods Overview § How Channels Are Selected

Step 6: BST Instruction Sent to CMB

SBA withdrawal orchestration sends the withdrawal instruction to the CMB BST service (cmb_stock_trans):

Withdrawal instruction processing chain:
  1. Withdrawal Service → SBA Withdrawal Orchestration → CMB BST Service
  2. CMB BST Service encrypts request with SM2 national cipher algorithm
  3. Sends via Socket to CMB's exit_server
  4. CMB processes and returns result

SM2 encryption flow:

  1. Load Futu private key
  2. Load CMB public key certificate
  3. Sign + encrypt request data
  4. Base64 encode and send

Step 7: Bank Callback & Task Completion

After CMB finishes processing, it calls back the system via the BST bidirectional link:

Callback ResultProcessing
result = 0 (success)Task status → 2 (DONE)
result = -5 (timeout)Auto-switch to backup exit_server and retry
result = -6 (bank rejected)Task marked as failed, requires manual handling

Our transaction succeeds normally. Task status updates to DONE, and the user receives a "Withdrawal Successful" push notification.

End-to-end time from submission to receipt: BST channel is event-driven, typically seconds to a few minutes.


Deposit vs Withdrawal: Key Differences at a Glance

DimensionDepositWithdrawal
DirectionUser bank → Securities accountSecurities account → User bank
Method Count1012
Core MechanismAutomatic matching engine (five-dimensional)Three-step approval workflow
Automation Conditions5 auto-deposit conditions6 BST auto-withdrawal conditions
Daily Limit10 per user (auto-deposit)10 per user (BST auto)
Status Count6 (PENDING→DONE)6 (PENDING→DONE)
SBA Mode6 deposit orchestration modesUnified withdrawal orchestration
Risk ControlDeposit blacklist + whitelistWithdrawal blacklist + high-risk detection
Volume DistributioneDDA ~78%, ICBC ~12%, Others ~10%

Where to Go After Reading

I want to...Go to
Look up a termGlossary
See the 32-service layered architectureArchitecture & Data Flow
See all 10 deposit methodsDeposit Methods Overview
See all 12 withdrawal channelsWithdrawal Methods Overview
See a specific bank's complete rulesBank Capability Matrix
Understand how risk control blocks transactionsDeposit Troubleshooting, Withdrawal Troubleshooting
Learn about refund and reversal mechanismsRefunds & Reversals
Understand SBA orchestrationSBA Concepts & Data Model
Was this page helpful?

内部业务文档 · 仅限 moomoo 团队使用