OptionalexistingWalletId?: stringOptionallabel?: stringLabel for a newly-created vault wallet; ignored when existingWalletId
is given (that wallet already has a name we cannot change — Utila has no
rename). Defaults to the entity's display name.
This is the label only: SWEEP_WALLET_NAME_PREFIX is always applied on top, so an operator cannot accidentally mint a wallet that reads as custodial in a shared vault.
Operator-supplied because an entity being given a replacement wallet cannot reuse the retired one's name while that wallet is still around, and only the operator knows what distinguishes this generation.
Soft-delete or restore a deposit wallet, and mirror the same transition onto the Utila wallet by archiving / un-archiving it.
Deleting drops the wallet out of every consumer read — the customer
dashboard stops offering it as a deposit target — and archives it in the
vault, which also takes it out of listWallets (archived wallets are
excluded unless showArchived is set) so a retired wallet cannot be
offered back up for linking. Restoring is the exact inverse.
The DB write comes first, deliberately. Archiving first and then failing the update would leave a wallet that is archived in the vault but still live in CFX — a customer's deposit page pointing at a retired wallet. In this order the worst case is the benign one: hidden in CFX, still un-archived in the vault, which a retry fixes.
The Utila call is best-effort. It runs after a committed DB write, so
there is nothing useful to propagate and no way to roll back; a vault
outage must not stop an operator hiding addresses from a customer. It is
also the reason this method still works on a stage with no signer
credentials, where the call throws immediately. The outcome is reported as
archiveFailed rather than swallowed, so the caller can say so.
ProtectedentityThe wallet owner's display name — the identity's full name for a person,
the organization's name for a business. Built here rather than inlined
because it is needed twice: once in the projection and once in the q
predicate (Postgres can't reference a select alias from WHERE).
Wallets that exist in the sweep vault but aren't linked to an entity yet — the candidate set for the link flow. Sourced live from Utila (the vault is the authority on what exists) minus every wallet id already in the table.
The "already linked" read is deliberately unfiltered: a soft-deleted row still owns its Utila wallet, so offering it up for re-linking would produce two rows pointing at one wallet. Restoring the existing row is the correct operator move there, and keeping it out of this list is what forces it.
OptionalcreatedAt?: DbTimestampCriteriaOptionalcustomerIds?: string[]OptionalentityIds?: string[]OptionalentityTypes?: ("PERSON" | "BUSINESS")[]Narrow to wallets owned by people (identity_id) or by businesses
(organization_id). Distinct from entityIds, which names specific
entities — this is the "all people" / "all businesses" cut.
Optionalids?: string[]OptionalincludeDeleted?: booleanInclude soft-deleted wallets. Off by default so every caller that forgets it gets the live set. Admin-only: the consumer service has no such flag, because a deleted wallet is precisely one a customer must not see.
OptionalorderBy?: DbOrderByCriterion<Optionalpage?: numberDefaults to 1
OptionalpageSize?: numberDefaults to 10
Optionalq?: stringCase-insensitive substring over the Utila wallet id, the owning customer's name, the entity's name, and the derived deposit addresses — an operator most often arrives holding an address off a block explorer and needs the wallet it belongs to.
OptionalupdatedAt?: DbTimestampCriteriaHide or restore ONE derived address, leaving the wallet and every other chain alone.
The wallet-level delete above is all-or-nothing; this is the same contract
one level down, stored as a deletedAt stamp on the address entry inside
the data jsonb. Utila is not called and the vault is untouched: the
address keeps existing, so funds already sent to it still arrive and sweep.
What changes is that CFX stops offering it on the customer's deposit page.
Read-modify-write under a row lock, because every chain's addresses share one jsonb blob — two concurrent hides on different chains would otherwise race, and the second write would silently drop the first.
How many chains a fully-derived sweep wallet has addresses on — the denominator for "3 chains" on a list row, which is otherwise unjudgeable.
Comes from the client's supported-chain set, which is a pure function of
the vault env (22 chains on prod, 7 on dev) and needs no credentials and no
network. Deliberately NOT the b2b.chain reference table: that lists every
chain CFX knows about, which would give a wrong (much larger) denominator.
How many of a customer's deposit wallets are live, and how many are hidden.
One scan with FILTER aggregates rather than two
searchcalls: the customer hub renders this per panel open, and the deleted count is only meaningful next to the live one — "2, 1 deleted" is a single fact about the customer, so it should cost a single round trip. Exact, unlike counting a capped page.