Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions apps/api/src/api/services/monerium-b2b/account-provisioning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface ProvisionMoneriumB2bAccountInput {
contactEmail: string;
destination: string;
externalSubjectId: string;
/** Fee policy in ppm below the reference rate; defaults to the agreed launch policy. */
/** Fee policy in ppm below the reference rate; defaults to Vortex's default fee policy (B1). */
floorPpm?: number;
forwarderAddress: string;
managerProfileId: string;
Expand All @@ -53,7 +53,7 @@ function normalizeAddress(value: string, name: string): string {
return value.trim().toLowerCase();
}

/** Launch fee policy (docs/adr-0005-monerium-b2b-onramp.md, B1): 12.5 bps target, 15 bps floor. */
/** Default fee policy (docs/adr-0005-monerium-b2b-onramp.md, B1): 12.5 bps target, 15 bps floor. */
export const DEFAULT_TARGET_PPM = 1_250;
export const DEFAULT_FLOOR_PPM = 1_500;
// Mirrors the implementation's immutable MAX_FEE_PPM (ADR-0005 table); the contract re-validates at deploy.
Expand Down Expand Up @@ -189,7 +189,7 @@ async function verifyForwarderOnChain(
}
}

// Mirrors the whitelabel KYB outcome for a reliance-onboarded corporate: these
// Mirrors the whitelabel KYB outcome for a Monerium-approved client: these
// profiles are onboarded and approved on Monerium's side before they are mapped
// here, so the local provider records are imported directly as approved
// (docs/operations-monerium-interface.md, profile lifecycle).
Expand Down Expand Up @@ -312,8 +312,8 @@ export async function provisionMoneriumB2bAccount(
let result: { account: { created: boolean; row: MoneriumAccount }; managedProfile: ProvisionManagedProfileResult };
try {
result = await sequelize.transaction(async transaction => {
// The pilot reliance scope is KYB'd corporates only, so the child is always a
// business entity. Every local row is created in this transaction so a late
// Every B2B client is mapped as a business (adr-0007 decision 8), so the child is
// always a business entity. Every local row is created in this transaction so a late
// account conflict cannot leave an orphaned approved identity behind.
const managedProfile = await provisionManagedProfile(
{
Expand Down
3 changes: 1 addition & 2 deletions apps/api/src/api/services/monerium-b2b/dormancy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import { forwarderAbi, getGuardianWalletClient, getPublicClient } from "./chain"
* stays `active` — the pause lives on-chain, `dormant_since` records the detection.
*
* Un-pause is MANUAL for now: guardian ops call setGuardianPaused(false) after the
* partner re-confirms the client relationship — re-confirmation mechanics are a
* partner-agreement item (adr-0005 registry B5).
* partner re-confirms the destination in writing (adr-0005 registry B5).
*/

/** Dormancy pause window — registry P5 (docs/adr-0005-monerium-b2b-onramp.md). */
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/api/services/monerium-b2b/manager-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ async function emitDepositUpdatedEvents(deps: ManagerEventDeps): Promise<void> {

/** ACCOUNT_UPDATED: the account snapshot whenever it changed (IBAN issued, status, dormancy). */
async function emitAccountUpdatedEvents(): Promise<void> {
// ponytail: scans every mapped account each pass; fine at per-partner pilot scale.
// ponytail: scans every mapped account each pass; fine at pilot scale.
const accounts = await MoneriumAccount.findAll({ where: { vortexProfileId: { [Op.ne]: null } } });
for (const account of accounts) {
try {
Expand Down
6 changes: 3 additions & 3 deletions apps/api/src/api/services/monerium-b2b/recovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ import { refundAccountFor } from "./refund-wallet";
* IBAN, which pays out of the client's own IBAN, and mark the deposit `refunded` when
* Monerium processed it.
*
* Crash safety rests on the refund wallet being dedicated and empty between refunds:
* every step re-derives what is still to do from the wallet's balances, so a lost
* Crash safety rests on the refund wallet being dedicated and empty between refunds (a
* payment memo-routed to it breaks that until refunded by hand: runbook §2.7): every step re-derives what is still to do from the wallet's balances, so a lost
* transaction hash never repeats a value-moving send (a top-up already on chain makes the
* remaining need zero). One recovery at a time PER CLIENT is what keeps those balances
* meaningful: the executor refuses a second `recover` for an account while one is in flight
Expand All @@ -58,7 +58,7 @@ import { refundAccountFor } from "./refund-wallet";
*/

export const REFUND_MEMO_PREFIX = "vortex-refund:";
/** Monerium requires a supporting document above this amount; such refunds stay manual (rollout G1). */
/** Monerium requires a supporting document from this amount; such refunds stay manual (runbook §2.7). */
export const SUPPORTING_DOCUMENT_THRESHOLD_EUR = 15_000;
/** Gas the refund wallet's own transactions use (approve, reverse swap, surplus transfer), with margin. */
const REFUND_WALLET_GAS_UNITS = 400_000n;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { afterEach, describe, expect, it, mock, setSystemTime, spyOn } from "bun:test";
import { classifyReferenceVenue, fetchCoinbaseProductStatus, fetchCoinbaseReference, isWithinReferenceBand } from "./reference-rate";

// The partner reference is the Coinbase EURC-USDC bid/ask midpoint (adr-0005 P12,
// The reference rate is the Coinbase EURC-USDC bid/ask midpoint (adr-0005 P12,
// amendment 2026-09-18): spot, no averaging, with a spread guard for thin books.

function serve(body: unknown, status = 200) {
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/api/services/monerium-b2b/reference-rate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { formatUnits, parseUnits } from "viem";

/**
* Partner reference rate for the forwarder fee bands (docs/adr-0005-monerium-b2b-onramp.md, P12):
* Reference rate for the forwarder fee bands (docs/adr-0005-monerium-b2b-onramp.md, P12):
* the Coinbase Exchange EURC-USDC bid/ask midpoint, read fresh before every swap and
* recorded on the execution row (rate, source, time) so the partner can check it against
* Coinbase's public ticker. Spot rather than an average (amendment 2026-09-18): an average
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/api/services/monerium-b2b/registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export interface RegistrationDeps {
* blamed on the partner's input.
*/
profileState(moneriumProfileId: string): Promise<MoneriumProfileState | null>;
/** The clone's CREATE2 address, bound to its destination, recovery address, launch fee policy and salt. */
/** The clone's CREATE2 address, bound to its destination, recovery address, default fee policy and salt. */
predictAddress(destination: Address, recoveryAddress: Address, salt: Hex): Promise<Address>;
isForwarder(address: Address): Promise<boolean>;
/** Simulates, then sends `deployForwarder` from the deployer key; a contract revert throws. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DataTypes, QueryInterface } from "sequelize";

// The forwarder prices swaps against a reference rate with a per-clone target and floor
// in parts per million (docs/adr-0005-monerium-b2b-onramp.md, B1/P11). The flat
// fee_bps mirror is replaced by both policy values; defaults are the agreed launch policy.
// fee_bps mirror is replaced by both policy values; defaults are the B1 default policy.
export async function up(queryInterface: QueryInterface): Promise<void> {
await queryInterface.addColumn("monerium_accounts", "target_ppm", {
allowNull: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DataTypes, QueryInterface } from "sequelize";

// Every swap is priced against a partner reference rate (the Coinbase bid/ask midpoint)
// Every swap is priced against a reference rate (the Coinbase bid/ask midpoint)
// and may draw a subsidy from the vault up to the keeper's tier for the chunk
// (docs/architecture-monerium-b2b-onramp.md, fees section). The reference, the chosen
// route and the tier are persisted before broadcast (crash-recovery calldata identity +
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/models/moneriumConversionExecution.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export interface MoneriumConversionExecutionAttributes {
subsidyRaw: string | null;
usdcNetRaw: string | null;
destination: string;
/** Partner reference the swap was priced against, ORACLE_DECIMALS; persisted before broadcast. */
/** Reference rate the swap was priced against, ORACLE_DECIMALS; persisted before broadcast. */
referenceRateRaw: string | null;
referenceSource: string | null;
referenceAt: Date | null;
Expand Down
2 changes: 1 addition & 1 deletion contracts/monerium-forwarder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Foundry project for the attestor-linked forwarder (Monerium B2B zero-touch onramp):
per-client EIP-1167 clones whose EIP-1271 `isValidSignature` accepts only the fixed
Monerium link message from the Vortex attestor, a conversion policy that swaps over a
factory-whitelisted Uniswap v3 route and settles the fill against a partner reference
factory-whitelisted Uniswap v3 route and settles the fill against a reference
rate (fee above the target, top-up from the shared `VortexSubsidyVault` below the floor,
Chainlink floor on the client's net), whole-payment forwarding (chunks accumulate as USDC on the
clone and leave in one `forward`), and a keeper-only, delay-gated `recover` to the client's refund
Expand Down
3 changes: 1 addition & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ The smaller set of general project documents stays directly in `docs/`:
| [`operations-brl-tax-id-claim-release.md`](operations-brl-tax-id-claim-release.md) | Operator runbook for releasing a BRL tax ID squatted through `createSubaccount` (RISK-026) |
| [`operations-demo-environment.md`](operations-demo-environment.md) | Setup and runbook for the sandbox sales-demo account |
| [`operations-legacy-schema-cleanup.md`](operations-legacy-schema-cleanup.md) | Deployment gates and recovery runbook for irreversible migrations 060-061 |
| [`operations-monerium-b2b-rollout.md`](operations-monerium-b2b-rollout.md) | Launch gates, deploy checklist, and terms inputs for the B2B onramp pilot |
| [`operations-monerium-b2b-rollout.md`](operations-monerium-b2b-rollout.md) | Deploy checklist, launch readiness, and open items ledger for the B2B onramp |
| [`operations-monerium-b2b-runbook.md`](operations-monerium-b2b-runbook.md) | Operator procedures for the B2B onramp: onboarding, incidents, alert triage, dormancy, migration |
| [`operations-monerium-interface.md`](operations-monerium-interface.md) | Monerium onramp boundary across the OAuth and white-label apps plus the profile, address, IBAN, and payment interface reference |
| [`operations-testing.md`](operations-testing.md) | Maintained test strategy and suite boundaries |
| [`product-dashboard.md`](product-dashboard.md) | Current dashboard product scope and acknowledged gaps |
| [`product-monerium-b2b-flow.md`](product-monerium-b2b-flow.md) | High-level end-to-end flow of the Monerium B2B onramp for Vortex, the partner and Monerium, with the open questions per party |
| [`proposal-mcp-server.md`](proposal-mcp-server.md) | Active, non-authoritative discussion draft |
| [`proposal-monerium-consumer-onramp.md`](proposal-monerium-consumer-onramp.md) | Phase-2 proposal for the consumer (Safe + passkey) Monerium onramp; the B2B variant shipped |
| [`proposal-api-driven-kyc-kyb.md`](proposal-api-driven-kyc-kyb.md) | Proposal for API-driven verification using preserved provider-specific workflows |
Expand Down
Loading
Loading