The escrow-transfer arm of the transaction search, as a view.
Same motivation as depositTransactionView (see schema/deposit.ts): the
inline 12-arm UNION serialises past RDS Proxy's 16KB parse limit and pins the
client session to a connection. Behind a view the runtime statement is tiny.
Two sub-arms, one per side:
DEBIT — every escrow. Funds leave the sender's wallet into the hold at
funding time, keyed on the funding status update's signature, scoped to
the escrow row's own customer_id.
CREDIT — a COMPLETED row with a recipient_ledger_account_id, keyed on the
release status update's signature and scoped to that ACCOUNT's customer.
Without it the recipient sees nothing: the commit signature lands in the
escrow's COMPLETED status update, and
the blockchain-deposit known_signatures CTE claims it for the recipient's
customer through recipient_ledger_account_id (see blockchainArm.ts),
suppressing the inbound-transfer row that would
otherwise stand in for this one.
The two customers are the same one whenever the service's own rule holds (a
recipient ledger account is the sender's customer's — ESCROW_ON_MINTFX.md §3).
The CREDIT arm reads the account's rather than the row's so that it and the
claim cannot disagree about scope if that rule is ever broken.
Single-mint invariant: MOVEUSD-only (see swap.ts), so the body gates to
token_symbol = 'MOVEUSD'. A PENDING escrow is a quote (no funds have
moved) and shows as PENDING, with no signature (API_V2.md §4.4.5).
The recipient is identified by phone until they attach a wallet, and is
usually external (not a platform customer). recipient_wallet is projected
into counterparty_address, and the recipient ledger account, once bound,
into counterparty_ledger_account_id; counterparty_customer_* stay NULL.
The caller-supplied filters live in
transaction-services/queries/escrowTransfer.ts as predicates on this view's
own projected columns, because a view takes no parameters. They are plain
contract-column comparisons emitted by the shared
transactionScalarConditions, so what matters here is what each filtered
column projects:
customer_id — the escrow row's own customer_external_id copy on the
DEBIT arm, the recipient ledger account's customer (rc.external_id) on
the CREDIT arm.
signature — the CREATED status update's signature on the DEBIT arm, the
CLAIMED one on the CREDIT arm.
Changing what those two project silently changes the filters. The column list
must also stay identical to the sibling arms, or the UNION breaks.
securityInvoker is required, not cosmetic — every underlying table has RLS
enabled, and without it the view would run with the owner's row visibility and
silently bypass the querying role's policies.
The escrow-transfer arm of the transaction search, as a view.
Same motivation as
depositTransactionView(seeschema/deposit.ts): the inline 12-arm UNION serialises past RDS Proxy's 16KB parse limit and pins the client session to a connection. Behind a view the runtime statement is tiny.Two sub-arms, one per side:
customer_id.COMPLETEDrow with arecipient_ledger_account_id, keyed on the release status update's signature and scoped to that ACCOUNT's customer. Without it the recipient sees nothing: the commit signature lands in the escrow'sCOMPLETEDstatus update, and the blockchain-depositknown_signaturesCTE claims it for the recipient's customer throughrecipient_ledger_account_id(seeblockchainArm.ts), suppressing the inbound-transfer row that would otherwise stand in for this one.The two customers are the same one whenever the service's own rule holds (a recipient ledger account is the sender's customer's — ESCROW_ON_MINTFX.md §3). The CREDIT arm reads the account's rather than the row's so that it and the claim cannot disagree about scope if that rule is ever broken.
Single-mint invariant: MOVEUSD-only (see
swap.ts), so the body gates totoken_symbol = 'MOVEUSD'. APENDINGescrow is a quote (no funds have moved) and shows asPENDING, with no signature (API_V2.md §4.4.5).The recipient is identified by phone until they attach a wallet, and is usually external (not a platform customer).
recipient_walletis projected intocounterparty_address, and the recipient ledger account, once bound, intocounterparty_ledger_account_id;counterparty_customer_*stay NULL.The caller-supplied filters live in
transaction-services/queries/escrowTransfer.tsas predicates on this view's own projected columns, because a view takes no parameters. They are plain contract-column comparisons emitted by the sharedtransactionScalarConditions, so what matters here is what each filtered column projects:customer_id— the escrow row's owncustomer_external_idcopy on the DEBIT arm, the recipient ledger account's customer (rc.external_id) on the CREDIT arm.signature— theCREATEDstatus update's signature on the DEBIT arm, theCLAIMEDone on the CREDIT arm.Changing what those two project silently changes the filters. The column list must also stay identical to the sibling arms, or the UNION breaks.
securityInvokeris required, not cosmetic — every underlying table has RLS enabled, and without it the view would run with the owner's row visibility and silently bypass the querying role's policies.