feat(realunit): introduce /quote/* endpoint family, deprecate /brokerbot/*#3783
Merged
Conversation
…bot/*
The `/v1/realunit/brokerbot/*` family was misnamed: only the on-chain
sell-flow ever talks to the Brokerbot smart contract. The price/quote
endpoints (`/price`, `/buyPrice`, `/buyShares`, `/sellPrice`,
`/sellShares`, `/info`) are pricing oracles fed by Aktionariat's REST
API (`/directinvestment/getPrice`, 30 s cache) — and the buy flow
itself is a fiat bank transfer + off-chain `payAndAllocate` call.
Calling that surface "brokerbot" leaked an implementation detail that
isn't even accurate.
Adds the additive `/quote/*` mirror family. Each new route delegates
to the same service method as its `/brokerbot/*` counterpart and
returns the same DTO shape, so the wire format is byte-identical for
existing clients. The legacy `/brokerbot/*` routes are kept and
annotated `deprecated: true` in Swagger so consumers see the
migration target without being broken.
Also adds a CONTRIBUTING section ("RealUnit: /quote/* vs /brokerbot/*")
that lays out which endpoints touch the on-chain Brokerbot vs which
are pure price oracles, so the naming distinction sticks past this PR.
- Move `getQuoteSellShares` out of its accidental position below the deprecated `/brokerbot/*` block and into the Quote group next to `getQuoteSellPrice`, mirroring the brokerbot ordering. - Reword the four `/quote/*` summaries from the novel `Quote: …` prefix to the controller's standard `Get …` verb form. - Replace the six deprecated `/brokerbot/*` summary descriptions (one of which still claimed the value came `from the Brokerbot smart contract`) with neutral pointers to the canonical `/quote/*` mirror. Keeps the deprecated routes from contradicting the new CONTRIBUTING section. - Rewrite the CONTRIBUTING table so every `PUT /sell*` route is listed with its actual on-chain footprint: `/sell`, `/sell/:id/unsigned-transactions` and `/sell/:id/confirm` all call `getBrokerbotSellPrice` (viem `readContract`); `/sell/:id/broadcast` does not — it only submits the signed tx.
…able The block comment introducing `/quote/*` still claimed the on-chain Brokerbot is touched in `unsigned-transactions + broadcast`, but the table that the previous fix commit put into CONTRIBUTING (and the service code itself) shows the on-chain reads happen in `PUT /sell` + `/sell/:id/unsigned-transactions` + `/sell/:id/confirm` — `/broadcast` only submits the signed transaction. Update the comment to match.
Collaborator
Author
|
Self-reviewed via independent subagent loop before flipping to ready:
|
davidleomay
approved these changes
May 28, 2026
TaprootFreak
added a commit
that referenced
this pull request
May 28, 2026
… /wallet/status The endpoint that drives the RealUnit registration UX historically lived under `/v1/realunit/wallet/status`. That path is misleading: the resource described is the user's Aktionariat registration, not a generic wallet status, and clients never ask "what is the wallet's status?" — they ask "what do I need to do to be RealUnit-registered?". Following the precedent set by the `/quote/*` vs `/brokerbot/*` rename (PR #3783), this commit: - adds `GET /v1/realunit/registration` as the canonical endpoint - keeps `GET /v1/realunit/wallet/status` as a `deprecated: true` mirror that calls the same service method and returns the same DTO instance - renames `RealUnitWalletStatusDto` to `RealUnitRegistrationInfoDto` (wire-neutral: TS class names don't appear on the JSON; field names `state` / `userData` / `isRegistered` are unchanged) - renames `RealUnitService.getAddressWalletStatus` to `getRegistrationInfo`; both controller routes delegate to it - extends CONTRIBUTING.md "API Design" with a sister-section to the `/quote/*` rename, summarising the old→new mapping and the operational consequence (legacy path kept for backwards compatibility on existing clients only)
TaprootFreak
added a commit
that referenced
this pull request
May 28, 2026
) * feat(realunit): pre-fill registration form from existing KYC data Users with completed DFX KYC who initiate a RealUnit purchase get sent through the Aktionariat registration flow, where the form controllers currently start empty. They must retype data the backend already holds, and `completeRegistration`'s `isPersonalDataMatching` rejects any deviation byte-for-byte — turning a one-tap signing step into a guessing game. Make `GET /v1/realunit/wallet/status` fall back to the underlying `user_data` record when no `RealUnitRegistration` KycStep exists yet. The app already consumes `RealUnitWalletStatusDto.userData` for the merge-existing-registration path; this extends the same shape to first-time registrations so the form can pre-fill with values that will pass server-side validation verbatim. Controller loads the country / nationality / language relations needed by the new mapper. Mapper degrades gracefully: no firstname/surname → `userData: undefined` (back to manual entry, same as before this PR). * feat(realunit): expose registration state on wallet/status Add a four-state discriminator (alreadyRegistered, addWallet, newRegistration, kycRequired) to GET /v1/realunit/wallet/status so the app can route to the right UX without inferring it locally. isRegistered is preserved unchanged for backwards compatibility and remains semantically equivalent to state === alreadyRegistered. * fix(realunit): address self-review on the registration-state field - Mark `isRegistered` with `@ApiProperty({ deprecated: true })` so Swagger UI and generated clients render the strikethrough — the prose-only deprecation in the previous commit relied on consumers reading the description text. - Switch `RealUnitRegistrationState` enum values from camelCase (`alreadyRegistered`, …) to the CONTRIBUTING-mandated PascalCase (`AlreadyRegistered`, …). The pre-existing `RealUnitRegistrationStatus` enum in this file uses snake_case which is also non-compliant, but that's a separate consumer-breaking rename and stays out of scope here — the new enum follows the rule. - Reword the `state` field description as four short `<value>: <action>` clauses separated by periods instead of the arrow-separated single sentence, so the rendered OpenAPI/Swagger output stays readable in ASCII-only tooling. * feat(realunit): expose /registration as canonical endpoint, deprecate /wallet/status The endpoint that drives the RealUnit registration UX historically lived under `/v1/realunit/wallet/status`. That path is misleading: the resource described is the user's Aktionariat registration, not a generic wallet status, and clients never ask "what is the wallet's status?" — they ask "what do I need to do to be RealUnit-registered?". Following the precedent set by the `/quote/*` vs `/brokerbot/*` rename (PR #3783), this commit: - adds `GET /v1/realunit/registration` as the canonical endpoint - keeps `GET /v1/realunit/wallet/status` as a `deprecated: true` mirror that calls the same service method and returns the same DTO instance - renames `RealUnitWalletStatusDto` to `RealUnitRegistrationInfoDto` (wire-neutral: TS class names don't appear on the JSON; field names `state` / `userData` / `isRegistered` are unchanged) - renames `RealUnitService.getAddressWalletStatus` to `getRegistrationInfo`; both controller routes delegate to it - extends CONTRIBUTING.md "API Design" with a sister-section to the `/quote/*` rename, summarising the old→new mapping and the operational consequence (legacy path kept for backwards compatibility on existing clients only)
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces a
/v1/realunit/quote/*mirror of the existing/v1/realunit/brokerbot/*routes. The mirror is the correctly-named, forward-going API surface; the legacy paths stay live but are now annotateddeprecated: truein Swagger. Wire format is byte-identical — same service methods, same DTO shapes — so consumers can migrate at their own pace without breakage.Why
The
brokerbot/*family name leaks an implementation detail that is, on top of being internal, mostly wrong:GET /brokerbot/price/buyPrice/buyShares/sellPrice/sellShares/infoare pricing oracles. They call Aktionariat's REST API (/directinvestment/getPrice, 30 s cache). They never touch the on-chain Brokerbot smart contract.PUT /buyis a fiat bank-transfer flow. Aktionariat allocates the shares off-chain viadirectinvestment/payAndAllocate. No Brokerbot smart contract involvement.PUT /sell/:id/unsigned-transactions+/broadcastplusRealUnitBlockchainService.getBrokerbotSellPrice— actually invokes the on-chain Brokerbot smart contract (the user signs an EIP-7702 transaction that we then broadcast to it).Calling the entire price oracle surface "brokerbot" misleads every reader who looks at the controller and assumes there's an on-chain dependency.
What changed
src/subdomains/supporting/realunit/controllers/realunit.controller.ts--- Quote Endpoints ---adds 6 routes mirroring the brokerbot ones:GET /quote/info→ delegates togetBrokerbotInfoGET /quote/price→ delegates togetBrokerbotPriceGET /quote/buyPrice?shares=N→ delegates togetBrokerbotBuyPriceGET /quote/buyShares?amount=N→ delegates togetBrokerbotBuySharesGET /quote/sellPrice?shares=N→ delegates togetBrokerbotSellPrice(auth-guarded as before)GET /quote/sellShares?amount=N→ delegates togetBrokerbotSellShares(auth-guarded as before)brokerbot/*routes getdeprecated: trueon@ApiOperation. Same handlers, same DTOs, same behaviour — only the Swagger flag changes.CONTRIBUTING.md/quote/*as cacheable pricing API; keepgetBrokerbot…naming for the genuine on-chain methods only).What did not change
BrokerbotPriceDto,BrokerbotBuyPriceDto, …). The wire JSON shape is part of the consumer contract; renaming the TypeScript classes would force a coordinated client migration that is out of scope for an additive rename.RealUnitBlockchainServicemethods.getBrokerbotSellPrice/getBrokerbotInfokeep their names because those do concern the on-chain Brokerbot contract.brokerbotAddress), the EIP-7702 delegation service references — anything that genuinely talks to the on-chain contract stays named as it was.Backwards compatibility
100 % additive. No existing client breaks.
/v1/realunit/brokerbot/*routes continue to work, return the same response, with the same authentication requirements./v1/realunit/quote/*routes are available as the migration target.Verification
npm run lint→ cleannpm run format:check→ cleannpm run build→ cleannpm test -- --testPathPattern=realunit.service→ 14 / 14 passing (no behavioural change to assert against; existing brokerbot wiring is untouched)