Real XMR pilot

This commit is contained in:
2026-10-22 14:40:00 -04:00
parent 52559f65d7
commit 3f04c3afa9
19 changed files with 408 additions and 50 deletions
+6 -4
View File
@@ -4,10 +4,12 @@ import { join } from 'node:path';
import { CustodyMarket } from './custody.ts';
import { PostgresCustody, type CustodyOptions } from './postgres-custody.ts';
import { custodyStorage, postgresConfig } from './postgres-config.ts';
import { PROFILE } from '../../shared/network.ts';
/** No automatic SQLite reinterpretation or fallback after a database connection/configuration failure. */
export async function openCustodyStorage(directory: string, options: CustodyOptions, env = process.env): Promise<CustodyMarket | PostgresCustody> {
const storage = custodyStorage(env), marker = join(directory, 'testnet', 'custody-postgres.json');
const profileDirectory = join(directory, PROFILE);
const storage = custodyStorage(env), marker = join(profileDirectory, 'custody-postgres.json');
const observerMode = env.WIKIDECK_CUSTODY_CANONICAL_REHEARSAL;
if (observerMode !== undefined && observerMode !== '0' && observerMode !== '1') {
throw new Error('WIKIDECK_CUSTODY_CANONICAL_REHEARSAL must be exactly 0 or 1');
@@ -16,7 +18,7 @@ export async function openCustodyStorage(directory: string, options: CustodyOpti
throw new Error('Canonical observer rehearsal requires PostgreSQL and the disposable database test guard');
}
const custodyOptions = observerMode === '1' ? { ...options, disposableSaleRehearsal: true } : options;
await mkdir(join(directory, 'testnet'), { recursive: true, mode: 0o700 });
await mkdir(profileDirectory, { recursive: true, mode: 0o700 });
let existing: { version: number; custodianId: string } | undefined;
try { existing = JSON.parse(await readFile(marker, 'utf8')); }
catch (e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; }
@@ -24,7 +26,7 @@ export async function openCustodyStorage(directory: string, options: CustodyOpti
if (existing) throw new Error('Custody data directory is bound to PostgreSQL; SQLite fallback prohibited');
return CustodyMarket.open(directory, custodyOptions);
}
const source = join(directory, 'testnet', 'custody-sandbox.sqlite');
const source = join(profileDirectory, 'custody-sandbox.sqlite');
let frozen: string | undefined;
try {
const info = await lstat(source);
@@ -44,7 +46,7 @@ export async function openCustodyStorage(directory: string, options: CustodyOpti
try { await handle.writeFile(JSON.stringify({ version: 1, custodianId: market.id })); await handle.sync(); }
finally { await handle.close(); }
if (process.platform !== 'win32') {
const parent = await open(join(directory, 'testnet'), 'r');
const parent = await open(profileDirectory, 'r');
try { await parent.sync(); } finally { await parent.close(); }
}
}
+2 -2
View File
@@ -2,7 +2,7 @@ import { DatabaseSync } from 'node:sqlite';
import { createHash, randomUUID } from 'node:crypto';
import { mkdir, chmod } from 'node:fs/promises';
import { join } from 'node:path';
import { IS_MAINNET } from '../../shared/network.ts';
import { IS_MAINNET, PROFILE } from '../../shared/network.ts';
import { NETWORK } from '../../shared/testnet.ts';
import { ADDITIONAL_MARKET_FEE } from '../../shared/market.ts';
import { allocateXmrSale } from '../../shared/xmr-pricing.ts';
@@ -50,7 +50,7 @@ export class CustodyMarket {
if (IS_MAINNET) throw new Error('Custody sandbox cannot run on mainnet');
await validateMarketPolicy(options);
if (!Number.isSafeInteger(options.feeBps) || options.feeBps < 0 || options.feeBps > 5000) throw new Error('Invalid custody fee');
const folder = join(directory, 'testnet');
const folder = join(directory, PROFILE);
await mkdir(folder, { recursive: true, mode: 0o700 });
const file = join(folder, 'custody-sandbox.sqlite');
const db = new DatabaseSync(file);
+2 -1
View File
@@ -16,6 +16,7 @@ import { RpcError } from '../resources.ts';
import type { CanonicalEvents, IndexedNft } from '../testnet/canonical-index.ts';
import { z } from 'zod';
import { operatorMarketPolicy, resolvedMarketPolicy, permitsMarketAction, validateMarketPolicy, type MarketPolicy } from './policy.ts';
import { PROFILE } from '../../shared/network.ts';
type Chain = { snapshot(): TestnetSnapshot; summary?(): { tip: string; revision: number; height?: number };
submitTransfer(raw: unknown): Promise<string>; nft?(token: string): IndexedNft | undefined;
@@ -112,7 +113,7 @@ export class Market {
static async open(directory: string, chain: Chain, config = marketConfig(), now = Date.now,
reconciliation: { worker?: boolean } = {}): Promise<Market> {
await validateMarketPolicy(config);
const folder = join(directory, NETWORK.includes('mainnet') ? 'mainnet' : 'testnet');
const folder = join(directory, PROFILE);
await mkdir(folder, { recursive: true, mode: 0o700 });
const file = join(folder, 'market.sqlite');
const db = new DatabaseSync(file);