/**
* rExchange module — P2P crypto/fiat exchange within communities.
*
* Community members post buy/sell intents for CRDT tokens (cUSDC, $MYCO, fUSDC)
* against fiat currencies. Solver matches intents, escrow handles settlement.
*
* All state stored in Automerge documents via SyncServer.
* Doc layout:
* {space}:rexchange:intents → ExchangeIntentsDoc
* {space}:rexchange:trades → ExchangeTradesDoc
* {space}:rexchange:reputation → ExchangeReputationDoc
*/
import { Hono } from 'hono';
import { renderShell } from '../../server/shell';
import { getModuleInfoList } from '../../shared/module';
import type { RSpaceModule } from '../../shared/module';
import type { SyncServer } from '../../server/local-first/sync-server';
import { renderLanding } from './landing';
import {
exchangeIntentsSchema, exchangeTradesSchema, exchangeReputationSchema,
} from './schemas';
import { createExchangeRoutes, startSolverCron, stopSolverCron } from './exchange-routes';
const routes = new Hono();
// ── SyncServer ref (set during onInit) ──
let _syncServer: SyncServer | null = null;
// ── Mount exchange routes ──
const exchangeRoutes = createExchangeRoutes(() => _syncServer);
routes.route('/', exchangeRoutes);
// ── Page routes ──
routes.get('/', (c) => {
const space = c.req.param('space') || 'demo';
return c.html(renderShell({
title: `${space} — rExchange | rSpace`,
moduleId: 'rexchange',
spaceSlug: space,
modules: getModuleInfoList(),
theme: 'dark',
body: ``,
scripts: ``,
}));
});
// ── Module export ──
export const exchangeModule: RSpaceModule = {
id: 'rexchange',
name: 'rExchange',
icon: '💱',
description: 'P2P crypto/fiat exchange with escrow & reputation',
canvasShapes: ['folk-exchange-node'],
canvasToolIds: ['create_exchange_node'],
scoping: { defaultScope: 'space', userConfigurable: false },
docSchemas: [
{ pattern: '{space}:rexchange:intents', description: 'Buy/sell intent order book', init: exchangeIntentsSchema.init },
{ pattern: '{space}:rexchange:trades', description: 'Active and historical trades', init: exchangeTradesSchema.init },
{ pattern: '{space}:rexchange:reputation', description: 'Per-member exchange reputation', init: exchangeReputationSchema.init },
],
routes,
landingPage: renderLanding,
async onInit(ctx) {
_syncServer = ctx.syncServer;
startSolverCron(() => _syncServer);
},
feeds: [
{
id: 'exchange-trades',
name: 'Exchange Trades',
kind: 'economic',
description: 'P2P exchange trade completions',
filterable: true,
},
],
outputPaths: [
{ path: 'canvas', name: 'Order Book', icon: '📊', description: 'Visual order book with buy/sell orbs' },
{ path: 'collaborate', name: 'My Trades', icon: '🤝', description: 'Active trades and chat' },
],
onboardingActions: [
{ label: 'Post Intent', icon: '💱', description: 'Post a buy or sell intent', type: 'create', href: '/rexchange' },
],
};