mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-25 01:58:33 +02:00
Recon of the operator's LAN BTCPay box (ssh four-btcpay / 10.42.1.33) showed the
real topology: BTCPay Server 2.3.9 handles BTC/LTC only (BTCPAY_CHAINS=ltc,btc),
while XMR and WOW run through separate 'xmrcheckout' (:8080) and 'wowcheckout'
(:8180) apps — and crucially, both expose a BTCPay-Greenfield-COMPATIBLE API
(/api/v1/stores/{id}/invoices, token auth, Settled/New/Expired status). Grin
isn't deployed there yet. So one Greenfield client class serves all three.
- btcpayProvider: id is now constructor-configurable so the same class registers
as 'btcpay' (BTC/LTC), 'xmrcheckout' (XMR), and 'wowcheckout' (WOW).
- buildProviderRegistry: activates each gateway independently from its *_URL/
_STORE_ID/_API_KEY trio (BTCPAY_*, XMRCHECKOUT_*, WOWCHECKOUT_*), with
topology-correct default routing (BTC/LTC->btcpay, XMR/WOW->their checkout or
native), BTCPAY_CHAINS to widen, PAYMENT_ROUTING to override.
- gameModeManager: takes an optional paymentProviders registry (defaults to a
native-wrapping registry built from walletService). createPaymentRequest now
creates the invoice via getProvider(cryptoType).createInvoice(...). The native
provider delegates to walletService.createPaymentRequest, so the shipped
single-chain config is byte-for-byte unchanged — same subaddress, same
monitoring maps. paymentRequest now also carries invoiceId for the monitoring
wire to come.
- nativeMoneroProvider: surfaces addressIndex so the call site stays provider-agnostic.
Behavior-preserving: no gateway env => native-only, every chain routes native.
Monitoring + payout paths intentionally left on the native path this pass;
gateway monitoring (provider.startWatch) is the flagged next step. Tests: +4
(provider wiring routes to a gateway; default registry delegates to native).
Suite 53 suites / 365 tests green.
69 lines
3.3 KiB
JavaScript
69 lines
3.3 KiB
JavaScript
/**
|
|
* Proves GameModeManager.createPaymentRequest routes invoice creation through the payment-provider
|
|
* registry: a configured gateway is used, and with the default registry it delegates to the native
|
|
* walletService (byte-for-byte legacy path).
|
|
*/
|
|
const GameModeManager = require('../src/game/gameModeManager');
|
|
|
|
function mockDb() {
|
|
return {
|
|
query: jest.fn(async (sql) => {
|
|
const s = String(sql);
|
|
if (/FROM users WHERE id/i.test(s)) return { rows: [{ id: 7, credits: 0, total_credits_purchased: 0 }] };
|
|
if (/INSERT INTO payments/i.test(s)) return { rows: [{ id: 101, expires_at: null }] };
|
|
return { rows: [] }; // reuse lookup, expire-stale, everything else
|
|
}),
|
|
withTransaction: jest.fn(async (cb) => cb({ query: jest.fn().mockResolvedValue({ rows: [] }) }))
|
|
};
|
|
}
|
|
|
|
const mockDebug = { CONSOLE_LOGGING: false };
|
|
const mockConfig = {
|
|
getConfig: () => ({
|
|
paymentsEnabled: true,
|
|
currency: { symbol: 'WOW', decimals: 11 },
|
|
modes: { direct: { enabled: true, price: 100000000000n }, credits: { enabled: false, packages: [] } },
|
|
payouts: { rules: { direct: { multipliers: {} }, credits: { enabled: false, multipliers: {} } } },
|
|
preferences: {}
|
|
}),
|
|
getLegacyGameMode: () => 'PAID_SINGLE',
|
|
eventBus: { on: () => {} }
|
|
};
|
|
|
|
describe('createPaymentRequest routes through the provider registry', () => {
|
|
test('a configured gateway provider is used for invoice creation', async () => {
|
|
const gateway = {
|
|
id: 'xmrcheckout',
|
|
createInvoice: jest.fn(async () => ({ invoiceId: 'inv-uuid', address: 'GATEWAYADDR', addressIndex: null, expiresAt: null })),
|
|
getProvider() { return this; }
|
|
};
|
|
const registry = { getProvider: jest.fn(() => gateway) };
|
|
const walletService = { createPaymentRequest: jest.fn() };
|
|
const gmm = new GameModeManager(mockDb(), walletService, mockDebug, mockConfig, registry);
|
|
|
|
const res = await gmm.createPaymentRequest('sock1', 'single_game', { userId: 7 });
|
|
|
|
expect(registry.getProvider).toHaveBeenCalledWith(gmm.cryptoType);
|
|
expect(gateway.createInvoice).toHaveBeenCalledWith(
|
|
expect.objectContaining({ chain: gmm.cryptoType, userId: 7, orderId: 'sock1' })
|
|
);
|
|
expect(res.address).toBe('GATEWAYADDR');
|
|
expect(res.invoiceId).toBe('inv-uuid');
|
|
expect(walletService.createPaymentRequest).not.toHaveBeenCalled(); // routed away from native
|
|
});
|
|
|
|
test('the default registry delegates to the native walletService (legacy path preserved)', async () => {
|
|
const walletService = {
|
|
createPaymentRequest: jest.fn(async () => ({ address: 'NATIVEADDR', addressIndex: 3, expiresAt: null }))
|
|
};
|
|
// No injected registry -> constructor builds one whose only provider wraps this walletService.
|
|
const gmm = new GameModeManager(mockDb(), walletService, mockDebug, mockConfig);
|
|
|
|
const res = await gmm.createPaymentRequest('sock2', 'single_game', { userId: 7 });
|
|
|
|
expect(walletService.createPaymentRequest).toHaveBeenCalledWith(expect.anything(), expect.any(String), 7, 'sock2');
|
|
expect(res.address).toBe('NATIVEADDR');
|
|
expect(res.invoiceId).toBe('NATIVEADDR'); // native invoices keyed by subaddress
|
|
});
|
|
});
|