Conversation
…actory + unit tests
…solicited-USDC units
…ebhook inbox table
…-review r1 report
…k inbox, deposit processor
…ation, dormancy gate, cron worker
…IBAN issued to forwarder
…lidated), remainder re-arm, gap tests
…oks, terms inputs
Renumber the Monerium B2B migrations 051/052 to 069/070 past staging's current head (068); README additions ported into the rewritten layout.
The workspace and its scripts were committed without the matching bun.lock entry, so frozen-lockfile installs failed on this branch.
With the models registered, the postgres dropTable assigns options.supportsSearchPath during ENUM-type cleanup and throws on an undefined options argument. The migrator test suite now reverts across this migration (revertMigration to 066), so a bare dropTable aborted down() midway and left the schema partially dropped for every later integration suite.
Corporates that Monerium onboards to the whitelabel app under the partner's KYC reliance enter Vortex through an idempotent admin endpoint: it provisions the managed child (business entity), mirrors the approved KYB into provider_customers/kyc_cases, and binds the deployed forwarder as a monerium account owned by that profile via the new vortex_profile_id link. Divergent replays are conflicts, never overwrites; pre-mapping account rows are adopted when they match.
The keeper now advances every mapped onboarding account: attestor-signed address link and IBAN request run through the profile-scoped financial_operations ledger (exactly-once across crashes and retries), and the issued IBAN is recorded from the iban.updated webhook without ever overwriting an existing one (an IBAN change is the association monitor's alert condition). Activation after the penny test moves from raw SQL to an admin status endpoint gated on the issued IBAN.
GET /v1/monerium-b2b/account and /deposits let the partner manager (via X-Managed-Profile-Id delegation) or the child's own credential poll the account state and deposit-to-conversion history. Strictly effective-user scoped with the standard EU/business managed-profile policy; R09 unattributed inflows never surface. Docs and security spec updated for the EU corridor's B2B account scope.
DEPOSIT_RECEIVED and DEPOSIT_CONVERTED extend the webhook contract for business EUR onramp accounts: quoteless envelopes carrying the deposit and its conversion outcome, deliverable to the account's controlling manager. Existing transaction payloads are unchanged.
Deposit-family subscriptions register without a quote or session, are profile-owned only, and can never be mixed with transaction events or silently defaulted. Delivery goes through a new durable outbox (webhook_deliveries + claim-based dispatch worker with backoff, no webhook deactivation on outages) instead of the in-process retry loop. The monerium keeper emits DEPOSIT_RECEIVED at mint and DEPOSIT_CONVERTED at the 32-block notification depth, marked per deposit so each event fires exactly once and history never replays to late subscribers. Also fixes the webhook model validator that still hardcoded the legacy event pair.
The webhooks page gains the deposit-event family (registration rules, payload examples, durable at-least-once delivery semantics), the managed-profiles page narrows its no-webhooks statement to transaction events, and security-spec invariant 9 records the manager-owner delivery branch and the outbox.
The controller's own quoteId/sessionId presence check fired before the service's account-family branch, so the documented deposit-event registration always returned 400. The service owns that validation (transaction events need exactly one target, deposit events none); the new HTTP-level regression test goes through the real route, which the service-level tests bypassed.
Every open parameter gets a concrete recommendation to accept or overrule before deploy; T1 is rewritten as an open three-way decision, recording the pilot-only permissive-validator option under consideration together with the redeem-path and custody tradeoffs it carries.
One maintained end-to-end picture — onboarding and deposit-to-payout sequences, batching semantics, fee immutability, and the data model — with the security spec, registry, and runbooks as the detail layers.
A deposit bigger than perSwapCap could never be selected for any execution (eureIn is capped and only shrinks as the balance drains), so it stayed unallocated forever and head-of-line blocked attribution for every deposit behind it — DEPOSIT_CONVERTED never fired even though the funds converted correctly on chain. An oversized oldest deposit now attaches to the execution that begins converting it, with its pro-rata share clamped to the swapped amount so the allocation still sums exactly. Found while walking a worked example, not by the review.
P11 records the guardian-settable feeBps direction (timelocked increases, MAX_FEE_BPS cap) pending the 24h-vs-48h timelock choice; O1 records the backend-enforced migration procedure and why an on-chain timelock cannot gate an IBAN move.
P11 decided (Marcel, 2026-08-26): feeBps becomes guardian-adjustable within the immutable MAX_FEE_BPS. Increases announce on-chain and apply permissionlessly only after FEE_INCREASE_TIMELOCK (24 h), so a client whose SEPA transfer is in flight cannot be swapped under a silently higher fee; decreases and cancel-via-restate are immediate. The invariant suite's config-integrity check now tracks every legal fee transition through a ghost model instead of asserting immutability, and the backend config monitor reconciles guardian fee changes like other authorized transitions instead of alarming.
System map, onboarding and deposit-to-payout sequence diagrams, watcher/cursor mechanics, lifecycle state diagrams, an ER view of the data model, and the monitoring section — plus explicit labeling that the monerium_* tables belong exclusively to the B2B flow (the legacy OAuth integration owns no tables).
The forwarder whitelists the exact link/recovery message hashes, so an unannounced message change on Monerium's side fail-closes onboarding of new clients; an advance-notice obligation makes that a planned implementation update instead of a surprise outage.
The shared MoneriumApiService is now the single Monerium transport: the B2B module's internal whitelabel client is deleted and onboarding and monitoring call the shared client through a narrow adapter, keeping the dependency-injection seams intact. Credentials consolidate on MONERIUM_WHITELABEL_CLIENT_ID/SECRET and MONERIUM_API_URL (one whitelabel app = one credential set); MONERIUM_B2B_* keeps only the chain/keeper settings. The attestor's link message now aliases the shared constant so the signed and transmitted bytes cannot drift.
The committed vortex.openapi.d.ts predated a path reordering in vortex.openapi.json, so docs:api:check failed on a clean tree; this is the pinned generator's output for the unchanged spec.
Monerium confirmed (verbally, 2026-08-26) that issuer recovery presents the same 'I hereby declare that I am the address owner.' message as linking, whose hash the forwarder already whitelists: recovery works with the constrained validator as built, RECOVERY_HASH stays zero, and the pilot permissive-validator option is withdrawn. Written confirmation folds into G1 item 3. Also adds the O2 registry row: the immutable FEE_RECIPIENT treasury address and guardian key custody are deploy-time decisions.
P8 was decided 2026-07-17 (Chainlink EUR/USD weekend gaps observed up to 48h) and confirmed final today; the unit/fork/invariant configs still carried the 26h placeholder that would revert most weekends.
The docs/prd working set and docs/runbooks are absorbed into four maintained documents per docs/README.md rules: adr-0005 (decisions, final parameter registry, accepted risks), the architecture doc, operations-monerium-b2b-rollout (gates, deploy checklist, terms inputs), and operations-monerium-b2b-runbook (onboarding, incidents, triage, dormancy, migration). The consumer PRD survives as proposal-monerium-consumer-onramp; everything else lives in git history. All code and spec cross-references repointed.
The site emitted no description or og:* tags, so LinkedIn, X, Slack and messaging apps could not build a link preview for vortexfinance.co. The og:image is the existing 512px mark padded to 1200x630 on white so the preview works today; swap in a designed asset at public/og-image.png without touching code.
The placeholder was the 32px circle icon upscaled to 1200x630, so link previews were visibly pixelated. Render the navbar wordmark (blue.svg, recolored white) on the landing page's blue-950 background instead.
Monerium B2B onramp: forwarder contracts, keeper, managed-profile wiring, and deposit webhooks
Add Open Graph meta tags for link previews
✅ Deploy Preview for vortexfi ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for vrtx-dashboard canceled.
|
✅ Deploy Preview for vortex-sandbox ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
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.
No description provided.