Conversation
Introduces the Mykobo anchor integration surface in the shared package: singleton MykoboApiService with bearer auth + 401 retry, request/response types, EURC EvmToken on Base, Mykobo env vars, and an email field on RegisterRampRequest.additionalData to bind a ramp to a Mykobo profile.
Adds an EVM-to-SEPA quote strategy that swaps USDC to EURC on Base via Nabla and reads the anchor fee dynamically from Mykobo's /fees endpoint, mirroring the AlfredPay model (no static anchor table row). RouteResolver sends sepa+EVM to the new strategy while sepa+AssetHub stays on the existing Stellar path. Adds Mykobo-specific RampState meta fields and the locked-in implementation plan doc.
Adds the execution slab for the Mykobo EUR offramp targeting Base (EVM): - New evm-to-mykobo route prepares squidRouter (skipped when source is Base USDC), fee distribution, Nabla USDC->EURC swap, Mykobo intent creation, presigned EURC transfer to receivables, plus USDC/EURC/AXLUSDC cleanup approvals. - New mykoboPayoutOnBase phase handler broadcasts the EURC transfer and polls Mykobo until the transaction reaches COMPLETED. - subsidizePostSwap branches to mykoboPayoutOnBase for EUR offramps and routes EUR EVM offramps through the EVM subsidy path. - fundEphemeral now provisions a Base ephemeral for EUR offramps and only verifies user-submitted squid hashes when a blueprint exists. - base-chain post-process sweeps the new baseCleanupEurc phase alongside existing Base cleanups. - ramp controller captures req.ip into additionalData so the Mykobo intent request carries the user IP required by the API.
- Add integration test hitting real Mykobo dev sandbox (fees, intent, quote creation, registerRamp) without on-chain submission. - Fix OffRampFinalizeEngine to honor nablaSwapEvm output for SEPA path (not just PIX); previously SEPA quotes failed finalization. - Strip /v1 from default MYKOBO_BASE_URL; client appends it itself, so env var is now the bare host (https://api-dev.mykobo.app). - Ignore lastRampStateMykoboEur.json test artifact.
Introduces the mykoboOnrampDeposit RampPhase for the upcoming EVM ephemeral flow, an IbanPaymentData.reference field for SCOR payment references, EURC Base ERC20 constants, a free-token config for Mykobo EUR, and wires the new phase into the frontend progress page maps. Reuses the unified subsidizePreSwap / subsidizePostSwap / distributeFees handlers for the EVM branch instead of introducing suffixed phase names.
The unified subsidizePreSwap, subsidizePostSwap, nablaApprove, nablaSwap, and distributeFees handlers previously branched into the EVM path when the input or output currency was BRL (and a partial EURC special-case for offramp post-swap). This hardcoded the BRL flow into every handler and required a new conditional for each future EVM-ephemeral route. Switch the dispatch to check quote.metadata.nablaSwapEvm, which is set by the quote engine whenever the EVM-ephemeral Nabla path is selected (BRL today, Mykobo EUR onramp + offramp next). Removes the FiatToken import where it is no longer used.
Adds OnRampInitializeMykoboEngine which estimates EURC delivered on the Base ephemeral after Mykobo's deposit fee, populating ctx.mykoboMint for downstream stages. Introduces a Mykobo onramp validation helper that checks for an EVM ephemeral and EURC on Base, a MykoboApiService.defaultDepositFee shortcut to lookup MykoboFeeKind.DEPOSIT fees, the MykoboOnrampTransactionParams type carrying the user email, and a parallel ctx.mykoboMint shape next to ctx.aveniaMint / ctx.aveniaTransfer in the quote context.
Adds OnRampSwapEngineMykoboEvm, an EVM Nabla swap variant that consumes ctx.mykoboMint and swaps EURC -> USDC on Base, OnRampMykoboToEvmFeeEngine which carries the Mykobo deposit fee as the anchor fee and computes the Squidrouter network fee for Base USDC -> destination, and the onrampMykoboToEvmStrategy route strategy that chains Initialize -> Fee -> NablaSwap -> Discount -> SquidRouter -> Finalize. Reuses OnRampSquidRouterBrlToEvmEngineBase since it operates on USDC on Base regardless of upstream fiat origin.
Replace Monerium with Mykobo as the EUR→EVM onramp path: - RouteResolver: EURC + EVM destination → onrampMykoboToEvmStrategy - InitialPhaseHandler: EURC BUY → mykoboOnrampDeposit phase Monerium AssetHub strategy is retained for the substrate path.
Add OnrampMykobo kind to ramp-transaction-preparation that routes EURC BUY on EVM destinations to a new prepareMykoboToEvmOnrampTransactions route. RampService.prepareMykoboOnrampTransactions creates the Mykobo deposit intent (EURC, DEPOSIT, evm ephemeral address) and surfaces IBAN + reference via ibanPaymentData. Monerium remains for EURC -> AssetHub.
Mykobo on Base replaces Monerium for EUR onramps. EUR onramps now route exclusively through the Mykobo EVM-ephemeral flow; EUR→AssetHub is no longer supported and returns HTTP 400. - Delete Monerium controller, route, service, handlers, quote engines, strategies, transaction routes, and shared endpoint module - Drop `moneriumAuthToken`, `moneriumMint`, `moneriumOnrampSelfTransfer`, `moneriumOnrampMint` from phase/quote/meta types and validation - Remove EURC→Monerium branch from fund-ephemeral nextPhaseSelector and ramp helpers explorer-link builder - Drop `onrampMoneriumToAssethubStrategy` import and SEPA→AssetHub branch from route-resolver; EURC+AssetHub BUY now hard 400 - Drop `createOnrampSquidrouterTransactionsFromPolygonToMoonbeam` from shared squidrouter; retain Polygon→EVM path for Alfredpay USDT - Inline `Signature` type into ramp.endpoints (was re-exported from deleted Monerium endpoint module) - Update validation.test fixtures to use generic squid/nabla phases
Sweep removal of Monerium frontend integration: KYC machine, redirect step, AssetHub form step, auth service, hook, stories, schema fields, URL params, translations, and progress flow entries. Mykobo replacement UI will be added in a dedicated slab. - Delete moneriumKyc.machine, moneriumAuth, monerium.service, useMoneriumFlow, MoneriumRedirectStep, MoneriumAssethubFormStep, related stories - Remove ERC2612 permit branch and SEPA SELL message-signature branch from sign.actor; drop `moneriumOfframpSignature` and `moneriumOnrampPermit` from additionalData - Drop `moneriumWalletAddress` from useRampSubmission, schema, register payload, types.phases; EUR onramps deposit directly to evmEphemeral - Remove `useMoneriumKycActor`/`Selector`, MoneriumKyc types from contexts and machines/types - Simplify `getRampFlow`: EURC BUY always uses `onramp_eur_evm` (Mykobo flow). Drop `onramp_eur_assethub` and `onramp_eur_assethub_via_hydration` - Replace `onramp_eur_evm` flow with Mykobo: initial → mykoboOnrampDeposit → subsidizePreSwap → nablaApprove → nablaSwap → subsidizePostSwap → squidRouter* → distributeFees → destinationTransfer → complete - Drop `MoneriumErrors.USER_MINT_ADDRESS_NOT_FOUND` branch from useGetRampRegistrationErrorMessage and SummaryStep banner - Drop `ERC20_EURE_POLYGON_*` constants from shared tokens; remove all Monerium translation keys from en.json and pt.json
Poll the Base ephemeral for EURC arrival from Mykobo's SEPA settlement, then transition to subsidizePreSwap so the Nabla EURC→USDC swap can run. - Mirror BRLA/Alfredpay mint-handler structure: `checkEvmBalancePeriodically` on Base for EURC against `evmEphemeralAddress`, expected raw amount taken from `quote.metadata.mykoboMint.outputAmountRaw` - Recovery shortcut: skip the wait if the ephemeral already holds \u226595% of the expected amount (handles fee variance between quote and settlement) - 24h payment timeout reflects SEPA business-day cutoffs; on timeout the phase transitions to `failed`. Inner balance-check timeout (5 min) bubbles up as a recoverable error so the outer process loop can retry - Register `mykoboOnrampDepositHandler` alongside Mykobo payout handler Flow: initial \u2192 mykoboOnrampDeposit \u2192 subsidizePreSwap \u2192 nablaApprove \u2192 nablaSwap \u2192 subsidizePostSwap \u2192 squidRouter* \u2192 destinationTransfer
…ture EUR offramp migrated to Mykobo on Base/EVM; ARS to be rebuilt with AlfredPay later. This removes all Stellar token configs, Spacewalk redeem paths, SEP-10 auth, Stellar/Spacewalk phase handlers, Stellar tx builders/validation, StellarTokenConfig/Details types, Stellar ephemeral helpers, and stellar_eurc /stellar_ars anchor fee branches. FiatToken.ARS preserved for the frontend selector. ARS via 'cbu' now throws explicit 'temporarily unavailable' error in route-resolver. PaymentData.anchorTargetAccount removed (only Stellar callsites). XCM event parser moved to xcmParsers.ts so substrate event listener compiles without redeem parsers.
Deletes stellar_eurc and stellar_ars rows from anchors table and removes XLM-token subsidies, completing the Stellar removal. New migration (028); prior migrations 005/008/022 are left untouched.
…ring Deletes stellarKyc XState machine + SEP-10/24 actors and services, the useSignChallenge hook, and stellar.service. Strips stellar ephemeral creation from useRampSubmission, register.actor, and ramp.machine; removes stellarKyc branch from kyc.states; removes spacewalkRedeem/stellarPayment/stellarCreate Account from phaseFlows and phaseMessages; cleans up rampState context, ramp page, RampSubmitButton, NetworkSelector, TokenSelection helpers, summary TransactionTokensDisplay, storage.service, services/api/index re-export, phases types, localStorage keys, and progress flow resolver. ARS coin icon and FiatToken.ARS preserved for the token selector.
Drops createStellarEphemeral usage from VortexSdk, the stellarEphemeral field from SDK input/internal types, and BrlHandler's stellar ephemeral plumbing. SDK no longer signs Stellar transactions since the backend has no Stellar offramp paths.
…m fallback Refactors the bridged-token-for-fallback ternary into an explicit if/else that throws if Ethereum USDC config is missing. Removes the only Mykobo-scoped biome lint error introduced in this branch.
…hemeral from mykobo offramp test Slab 7 removed stellarTokenConfig, which was the only place FiatToken.EURC had fiat metadata registered, causing getAnyFiatTokenDetails(EURC) to throw 'Token type is not Moonbeam' in the offramp quote validation path. - Register FiatToken.EURC in freeTokenConfig with decimals=6 (Circle's EVM EURC on Base) and matching min/max amount caps. - Remove the leftover Stellar ephemeral from the mykobo-eur-offramp integration test now that the Mykobo+Base flow only needs EVM+Substrate ephemerals (the normalize step now rejects Stellar entries). Mykobo offramp integration test: 5/5 passing against real sandbox.
Mirrors mykobo-eur-offramp.integration.test.ts for BUY direction. Covers Mykobo /fees DEPOSIT lookup, createTransactionIntent DEPOSIT returning IBAN instructions, EUR onramp quote on Base, and ramp registration which calls Mykobo at registration time and populates ibanPaymentData + state.mykoboTransactionId/Reference. Asserts Base-destination phase set: nablaApprove, nablaSwap, destinationTransfer, baseCleanupEurc, baseCleanupUsdc; no SquidRouter. Adds gitignore entries for the test scratch file. All 5/5 tests pass against the real Mykobo sandbox.
…e flows Adds 05-integrations/mykobo.md covering the active EUR rail (SEPA <-> EURC on Base, mirroring BRLA-on-Base topology) with invariants, threat vectors, and audit checklist. Updates ramp-phase-flows.md corridor list, mermaids, handler-registry table, and audit checklist to reflect Mykobo on/offramp and the removal of the Stellar-EUR offramp and Monerium-EUR onramp.
…cated Adds deprecation banners pointing to mykobo.md. Stellar anchors remain active for ARS-only off-ramp; Monerium is fully removed from active corridors. Files retained for audit lineage of F-023 / F-024.
Updates module index, glossary, system architecture, ephemeral-account inventory, discount/validation notes, integration corridor lists, Spacewalk bridge intro, fund-routing F-029 (Mykobo Base ops added to MOONBEAM_FUNDING_PRIVATE_KEY blast radius), secret-management inventory (MYKOBO_* env vars added), and release-readiness env-var list (replace MONERIUM_* with MYKOBO_*). No code paths reference Monerium for new ramps; banners preserve audit lineage.
AUDIT-RESULTS.md: marks Section 5.2 Monerium DEPRECATED, adds Section 5.2b Mykobo with 21 checks (20 PASS, 1 PARTIAL log redaction, 1 FAIL on HTTP-client timeout per F-014), updates F-014 location list, marks F-023 SUPERSEDED and F-024 carried forward, retargets top-10 action item #9 to a per-user concurrent Mykobo-ramp limit. FINDINGS.md: F-014 service list now includes Mykobo+BRLA and notes the Monerium gap was inherited by the Mykobo client; F-023 status set to SUPERSEDED with resolution explaining the 24h Mykobo outer timeout; F-024 carried forward as DEFERRED — STILL APPLIES with the impact rewritten for the larger 24h exposure window per pending unpaid ramp.
- Rewrite ramp-phase-flows on-ramp and off-ramp mermaid diagrams as unified funnel-after-fiat: per-corridor fiat-watch entry collapses into the shared Pendulum/Nabla chain, then splits again at payout. - Correct EUR on-ramp prose: mykoboOnrampDeposit transitions directly to subsidizePreSwap, skipping fundEphemeral. - Remove ARS as an active corridor: drop ARS row from cross-chain delivery, drop ARS off-ramp branch from the diagram, and downgrade stellar-anchors.md from 'ARS-only' to fully deprecated. - Fix mykobo.md endpoint typo: /v1/mykobo/profile -> /v1/mykobo/profiles (matches mykobo.route.ts).
File four open findings raised during the Mykobo-on-Base EUR rail audit: - F-068 (Critical): /v1/mykobo/profiles GET/POST have no requireAuth; anonymous callers can enumerate KYC profiles by wallet address and POST KYC documents (ID, source-of-funds, selfie) against arbitrary wallet addresses. Parent mount at routes/v1/index.ts is also unwrapped. Violates mykobo.md Invariant 15. Fix: add requireAuth to both routes (mirroring alfredpay.route.ts) plus wallet-ownership check. - F-069 (High): fund-ephemeral-handler.nextPhaseSelector has no EURC SELL branch; EUR off-ramps fall through to 'moonbeamToPendulum', which has no role in Base-only EUR off-ramp routing (evm-to-mykobo.ts). Latent stuck-phase bug. Not surfaced by tests because integration tests only call registerRamp, not startRamp on this path. Fix: add explicit EURC -> distributeFees branch mirroring BRL. - F-070 (Medium): MykoboApiService constructor accepts any URL scheme for MYKOBO_BASE_URL. A misconfigured deployment with http:// would silently transmit bearer tokens, KYC document references, and IBAN payment instructions in cleartext. Fix: enforce URL.protocol === 'https:' in production. - F-071 (Low): MykoboApiService.handleAuthFailure is not debounced. Concurrent 401s trigger concurrent refresh/acquire calls (thundering herd), with this.cachedToken writes racing. getToken is correctly debounced via tokenPromise; apply the same pattern to the 401 path. Also flip the corresponding rows in AUDIT-RESULTS.md (Mykobo subsection 5.2b checks #2, #14, #17, #19) from PASS to FAIL/PARTIAL, update the summary tables in both files to reflect 4 open findings, and add the remediation entries to the Recommended Remediation Order.
Both GET and POST /v1/mykobo/profiles were unprotected, allowing anonymous callers to enumerate KYC profiles and submit arbitrary KYC documents. Adds requireAuth middleware on both routes, mirroring the alfredpay pattern. No wallet-ownership check needed: wallet_address in the Mykobo flow always refers to an ephemeral, not a user-owned wallet.
Mykobo Base EVM Integration
EUR→EURC on Base is degenerate: Mykobo settles the SEPA deposit directly as EURC on the Base ephemeral, so the generic Nabla(EURC→USDC)+Squid(USDC→EURC) path swaps a token for itself, wasting fees and exposing the ramp to a settlement-subsidy race. Add isEurToEurcBaseDirect() and short-circuit this corridor end to end: - quote: Nabla engine emits a 1:1 EURC passthrough; Squid engine emits a same-token same-chain record with skipRouteCalculation. - tx builder: emit only the destinationTransfer (and mark isDirectTransfer), skipping nabla/squid/cleanup txs. - fund-ephemeral: route the direct corridor straight to destinationTransfer.
The finalSettlementSubsidy handler returned as soon as any balance (incl. leftover dust from the Nabla swap) appeared on the ephemeral, then computed subsidy = expected - totalBalance. When the Squid bridge output had not yet landed, it over-subsidized: a EUR→EURC Base ramp received ~29.36 EURC from the funder on top of the bridge delivery, stranding ~59 EURC. - snapshot destination-token balance (preSettlementBalance) right after the squidRouter swap confirms, before squidRouterPay, so the subsidy reflects actual bridge delivery (actualBalance - preSettlementBalance) rather than total balance. - wait for >=90% of expected delivery before computing the subsidy. - defensively skip the subsidy/squidRouter phases for direct-transfer ramps.
When the source and destination chains are the same (EURC/BRLA on Base, AlfredPay token on Polygon), destinationTransfer was presigned with a nonce after the post-complete cleanup approvals. Since cleanups only broadcast at the 'complete' phase, the presigned nonce sat ahead of the ephemeral's live nonce and could never be mined, stranding user funds (0 delivered). Place destinationTransfer at the first executable nonce after the swap for same-chain routes, followed by the cleanup approvals. Backup re-swap txs are omitted on same-chain paths (no handler executes them and they would re-introduce the nonce gap).
Add a best-effort guard in DestinationTransferHandler that compares the presigned transaction nonce against the ephemeral's live on-chain nonce before broadcasting. If the presigned nonce is ahead of the live nonce, the transfer can never be mined, so raise an unrecoverable error for manual review instead of silently retrying until funds are stranded. RPC failures while reading the live nonce are non-blocking and fall through to the normal happy path.
Reframe the same-chain destination nonce invariant/threat from the misleading "nonce-0 collision" to the real failure mode — a nonce gap that leaves destinationTransfer permanently un-mineable and strands funds (0-delivery). Add the new destination-transfer fail-fast guard invariant, the finalSettlementSubsidy over-subsidy race fix, and the EUR→EURC-on-Base direct-transfer bypass across ramp-phase-flows, fund-routing, and mykobo specs.
The squidRouter phase handler skipped the swap for any AlfredPay onramp delivering to Polygon, keyed only on metadata.to (the destination network). Since AlfredPay mints USDT on Polygon, a USDC (or other token) output requires a real USDT->output swap; skipping it stranded funds. Gate the skip additionally on quote.outputCurrency === ALFREDPAY_EVM_TOKEN so only the direct-token (USDT/Polygon) case short-circuits, mirroring the quote engine's skipRouteCalculation condition. USDC/Polygon now falls through to execute the swap; USDT/Polygon and cross-chain are unaffected.
Avenia mints BRLA on Base, but the BRL→BRLA/Base corridor still forced an unconditional BRLA→USDC Nabla swap (a degenerate self-swap) that fails. Mirror the existing EUR→EURC Base direct path for BRL→BRLA: add an isBrlToBrlaBaseDirect predicate and wire it through the quote engines and phase handlers. The Avenia Nabla engine now bypasses the swap with 1:1 BRLA passthrough metadata, the shared Base SquidRouter engine emits a 1:1 passthrough bridge record, and the Avenia route emits a single destinationTransfer (nonce 0) with isDirectTransfer set — skipping the Nabla swap, fee-token distribution, SquidRouter, and both Base cleanups that only make sense when a BRLA→USDC swap actually happened. The fund-ephemeral, squidRouter, and finalSettlement handlers recognise the new direct predicate alongside the persisted isDirectTransfer flag, keeping BRL→BRLA structurally identical to the proven EUR→EURC corridor.
…ge cases Document the two degenerate no-swap on-ramp fixes alongside the existing EUR→EURC bypass: - Bug 1 (AlfredPay): the Polygon swap short-circuit must be gated on the output token (`quote.outputCurrency === ALFREDPAY_EVM_TOKEN`), not on the destination network alone — otherwise a non-USDT Polygon output (e.g. USDC) is mis-delivered as the minted USDT. Added invariant, threat, and checklist item to alfredpay.md; note in ramp-phase-flows.md. - Bug 2 (Avenia/BRLA): BRL→BRLA-on-Base must take the direct-transfer bypass (`isBrlToBrlaBaseDirect`) — single destinationTransfer, no Nabla/ distributeFees/Squid/finalSettlementSubsidy/cleanup. Added flow subsection, invariant, threat, and checklist items to brla.md; note in ramp-phase-flows.md; extended the degenerate-route invariant/checklist in fund-routing.md.
…ges-for-order-limits [READY] Improve Error Messages
Mykobo on Base improvements
Change subsidy guard from targetDiscount > 0 to targetDiscount !== 0 in all four discount engines so that negative configured targets (e.g., -0.001 for reference rate minus 10 bps) correctly compute and apply subsidies when actual output falls below the floor. - onramp.ts - offramp.ts - onramp-alfredpay.ts - offramp-alfredpay.ts Add unit tests for calculateSubsidyAmount covering: - Positive/negative/zero targetDiscount scenarios - Max subsidy cap behavior - Actual output meeting or exceeding target
Persists ephemeral keypairs to a separate localStorage item keyed by ramp ID, so they survive rampState resets. Includes security-spec documentation.
…alstorage-backup Add rampEphemerals localStorage backup for ephemeral key failsafe
…count Allow negative targetDiscount as rate floor
Delete expired quotes that are older than 90 days
✅ Deploy Preview for vortexfi ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ 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.