206 lines
5.1 KiB
TypeScript
206 lines
5.1 KiB
TypeScript
/**
|
|
* rExchange Schemas — P2P on/off-ramp exchange intents, trades, and reputation.
|
|
*
|
|
* DocId formats:
|
|
* {space}:rexchange:intents → ExchangeIntentsDoc (active buy/sell intents)
|
|
* {space}:rexchange:trades → ExchangeTradesDoc (active & historical trades)
|
|
* {space}:rexchange:reputation → ExchangeReputationDoc (per-member trading reputation)
|
|
*/
|
|
|
|
import type { DocSchema } from '../../shared/local-first/document';
|
|
|
|
// ── Enums / Literals ──
|
|
|
|
export type ExchangeSide = 'buy' | 'sell';
|
|
export type TokenId = 'cusdc' | 'myco' | 'fusdc';
|
|
export type FiatCurrency = 'EUR' | 'USD' | 'GBP' | 'BRL' | 'MXN' | 'INR' | 'NGN' | 'ARS';
|
|
export type RateType = 'fixed' | 'market_plus_bps';
|
|
export type IntentStatus = 'active' | 'matched' | 'completed' | 'cancelled' | 'expired';
|
|
|
|
export type TradeStatus =
|
|
| 'proposed'
|
|
| 'accepted'
|
|
| 'escrow_locked'
|
|
| 'fiat_sent'
|
|
| 'fiat_confirmed'
|
|
| 'completed'
|
|
| 'disputed'
|
|
| 'resolved'
|
|
| 'cancelled'
|
|
| 'timed_out';
|
|
|
|
// ── Exchange Intent ──
|
|
|
|
export interface ExchangeIntent {
|
|
id: string;
|
|
creatorDid: string;
|
|
creatorName: string;
|
|
side: ExchangeSide;
|
|
tokenId: TokenId;
|
|
fiatCurrency: FiatCurrency;
|
|
tokenAmountMin: number; // base units (6 decimals)
|
|
tokenAmountMax: number;
|
|
rateType: RateType;
|
|
rateFixed?: number; // fiat per token (e.g. 0.98 EUR/cUSDC)
|
|
rateMarketBps?: number; // basis points spread over market rate
|
|
paymentMethods: string[]; // "SEPA", "Revolut", "PIX", "M-Pesa", "Cash", etc.
|
|
isStandingOrder: boolean; // LP flag — re-activates after fill
|
|
autoAccept: boolean; // skip manual match acceptance
|
|
allowInstitutionalFallback: boolean; // escalate to HyperSwitch if unmatched
|
|
minCounterpartyReputation?: number; // 0-100
|
|
preferredCounterparties?: string[]; // DID list
|
|
status: IntentStatus;
|
|
createdAt: number;
|
|
expiresAt?: number;
|
|
}
|
|
|
|
// ── Trade Chat Message ──
|
|
|
|
export interface TradeChatMessage {
|
|
id: string;
|
|
senderDid: string;
|
|
senderName: string;
|
|
text: string;
|
|
timestamp: number;
|
|
}
|
|
|
|
// ── Exchange Trade ──
|
|
|
|
export interface ExchangeTrade {
|
|
id: string;
|
|
buyIntentId: string;
|
|
sellIntentId: string;
|
|
buyerDid: string;
|
|
buyerName: string;
|
|
sellerDid: string;
|
|
sellerName: string;
|
|
tokenId: TokenId;
|
|
tokenAmount: number; // agreed amount in base units
|
|
fiatCurrency: FiatCurrency;
|
|
fiatAmount: number; // agreed fiat amount
|
|
agreedRate: number; // fiat per token
|
|
paymentMethod: string;
|
|
escrowTxId?: string;
|
|
status: TradeStatus;
|
|
acceptances: Record<string, boolean>; // did → accepted?
|
|
chatMessages: TradeChatMessage[];
|
|
fiatConfirmDeadline?: number; // timestamp — 24h default
|
|
disputeReason?: string;
|
|
resolution?: 'released_to_buyer' | 'returned_to_seller';
|
|
createdAt: number;
|
|
completedAt?: number;
|
|
}
|
|
|
|
// ── Reputation ──
|
|
|
|
export interface ExchangeReputationRecord {
|
|
did: string;
|
|
tradesCompleted: number;
|
|
tradesCancelled: number;
|
|
disputesRaised: number;
|
|
disputesLost: number;
|
|
totalVolumeBase: number; // total token volume in base units
|
|
avgConfirmTimeMs: number;
|
|
score: number; // 0-100
|
|
badges: string[]; // 'verified_seller', 'liquidity_provider', 'top_trader'
|
|
}
|
|
|
|
// ── Documents ──
|
|
|
|
export interface ExchangeIntentsDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
intents: Record<string, ExchangeIntent>;
|
|
}
|
|
|
|
export interface ExchangeTradesDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
trades: Record<string, ExchangeTrade>;
|
|
}
|
|
|
|
export interface ExchangeReputationDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
records: Record<string, ExchangeReputationRecord>;
|
|
}
|
|
|
|
// ── DocId helpers ──
|
|
|
|
export function exchangeIntentsDocId(space: string) {
|
|
return `${space}:rexchange:intents` as const;
|
|
}
|
|
|
|
export function exchangeTradesDocId(space: string) {
|
|
return `${space}:rexchange:trades` as const;
|
|
}
|
|
|
|
export function exchangeReputationDocId(space: string) {
|
|
return `${space}:rexchange:reputation` as const;
|
|
}
|
|
|
|
// ── Schema registrations ──
|
|
|
|
export const exchangeIntentsSchema: DocSchema<ExchangeIntentsDoc> = {
|
|
module: 'rexchange',
|
|
collection: 'intents',
|
|
version: 1,
|
|
init: (): ExchangeIntentsDoc => ({
|
|
meta: {
|
|
module: 'rexchange',
|
|
collection: 'intents',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
intents: {},
|
|
}),
|
|
};
|
|
|
|
export const exchangeTradesSchema: DocSchema<ExchangeTradesDoc> = {
|
|
module: 'rexchange',
|
|
collection: 'trades',
|
|
version: 1,
|
|
init: (): ExchangeTradesDoc => ({
|
|
meta: {
|
|
module: 'rexchange',
|
|
collection: 'trades',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
trades: {},
|
|
}),
|
|
};
|
|
|
|
export const exchangeReputationSchema: DocSchema<ExchangeReputationDoc> = {
|
|
module: 'rexchange',
|
|
collection: 'reputation',
|
|
version: 1,
|
|
init: (): ExchangeReputationDoc => ({
|
|
meta: {
|
|
module: 'rexchange',
|
|
collection: 'reputation',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
records: {},
|
|
}),
|
|
};
|