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.
An escrow row holds exactly one customer_id — the sender's — so the row only
ever appears in the sender's ledger and is always a DEBIT (funds leave the
sender's wallet into the on-chain escrow PDA at create_escrow).
Single-mint invariant: MOVEUSD-only (see swap.ts), so the body gates to
token_symbol = 'MOVEUSD'. PENDING escrows are quotes (unsigned tx in
metadata, on-chain create not confirmed — no funds have moved), so they are
excluded; the view surfaces CREATED onward.
The recipient is identified by phone until they attach a wallet, and is
usually external (not a platform customer). recipient_wallet is projected
into other_wallet_address for completeness, but the
other_wallet_customer_* columns stay NULL — mapTransactionFromDb only
builds otherWallet when all three are present.
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 — customer.external_id.
signature — the CREATED history entry's signature.
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.An escrow row holds exactly one
customer_id— the sender's — so the row only ever appears in the sender's ledger and is always aDEBIT(funds leave the sender's wallet into the on-chain escrow PDA atcreate_escrow).Single-mint invariant: MOVEUSD-only (see
swap.ts), so the body gates totoken_symbol = 'MOVEUSD'.PENDINGescrows are quotes (unsigned tx in metadata, on-chain create not confirmed — no funds have moved), so they are excluded; the view surfacesCREATEDonward.The recipient is identified by phone until they attach a wallet, and is usually external (not a platform customer).
recipient_walletis projected intoother_wallet_addressfor completeness, but theother_wallet_customer_*columns stay NULL —mapTransactionFromDbonly buildsotherWalletwhen all three are present.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—customer.external_id.signature— theCREATEDhistory entry's signature.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.