mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-28 18:48:38 +01:00
fix: make monerogue direct-entry only
This commit is contained in:
@@ -86,13 +86,17 @@ describe('commerce disclosure and paid-action policy', () => {
|
||||
});
|
||||
|
||||
test('publishes conspicuous no-real-value monerogue.app scope and MIT operator boundary', () => {
|
||||
const disclosure = buildCommerceDisclosure(manager(), env({
|
||||
const disclosure = buildCommerceDisclosure(manager({
|
||||
creditsModeEnabled: false
|
||||
}), env({
|
||||
OPERATED_PRODUCT_PROFILE: 'such-monerogue-stagenet'
|
||||
}));
|
||||
|
||||
expect(disclosure.operatedProduct.scopeNotice).toContain('single-player 2×/3× outcomes are test gambling mechanics');
|
||||
expect(disclosure.operatedProduct.noRealValueNotice).toContain('NO REAL VALUE');
|
||||
expect(disclosure.operatedProduct.commerceSummary).toContain('never send mainnet XMR');
|
||||
expect(disclosure.operatedProduct.commerceSummary).toMatch(/never send mainnet XMR/i);
|
||||
expect(disclosure.operatedProduct.commerceSummary).toContain('Purchased-credit entry');
|
||||
expect(disclosure.service.paidCreditsEnabled).toBe(false);
|
||||
expect(disclosure.service.cryptoMatchPayoutsEnabled).toBe(false);
|
||||
expect(disclosure.software).toEqual(expect.objectContaining({
|
||||
license: 'MIT',
|
||||
|
||||
@@ -225,7 +225,7 @@ describe('EnvironmentValidator production launch gate', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('accepts the exact Such Software monerogue.app stagenet 2x/3x contract', () => {
|
||||
test('accepts the exact direct-only Such Software monerogue.app stagenet 2x/3x contract', () => {
|
||||
const env = productionEnv({
|
||||
OPERATED_PRODUCT_PROFILE: 'such-monerogue-stagenet',
|
||||
HOSTED_BY: 'https://monerogue.app',
|
||||
@@ -233,16 +233,14 @@ describe('EnvironmentValidator production launch gate', () => {
|
||||
OPERATOR_CONTACT_URL: 'mailto:apps@such.software',
|
||||
OPERATOR_CONTACT_LABEL: 'apps@such.software',
|
||||
FREE_PLAY_ENABLED: 'true',
|
||||
PAYMENT_MODES: 'direct,credits',
|
||||
PAYMENT_MODES: 'direct',
|
||||
DIRECT_PAYMENT_ENABLED: 'true',
|
||||
CREDITS_ENABLED: 'true',
|
||||
CREDITS_ENABLED: 'false',
|
||||
PAYOUTS_ENABLED: 'true',
|
||||
DIRECT_PAYOUTS_ENABLED: 'true',
|
||||
CREDITS_PAYOUTS_ENABLED: 'true',
|
||||
CREDITS_PAYOUTS_ENABLED: 'false',
|
||||
DIRECT_PAYOUT_ESCAPE: '2.0',
|
||||
DIRECT_PAYOUT_TREASURE: '3.0',
|
||||
CREDITS_PAYOUT_ESCAPE: '2.0',
|
||||
CREDITS_PAYOUT_TREASURE: '3.0',
|
||||
ALLOW_MAINNET_PAYOUTS: 'false',
|
||||
SOLO_ENABLED: 'true',
|
||||
TAVERN_ENABLED: 'true',
|
||||
@@ -251,11 +249,18 @@ describe('EnvironmentValidator production launch gate', () => {
|
||||
MATCH_PAYOUTS_ENABLED: 'false'
|
||||
});
|
||||
const operatedConfig = config({
|
||||
modes: {
|
||||
direct: { enabled: true, price: 10000n },
|
||||
credits: {
|
||||
enabled: false,
|
||||
packages: [{ id: 'small', credits: 10, price: 90000000000n }]
|
||||
}
|
||||
},
|
||||
payouts: {
|
||||
enabled: true,
|
||||
rules: {
|
||||
direct: { enabled: true },
|
||||
credits: { enabled: true }
|
||||
credits: { enabled: false }
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -365,6 +370,9 @@ describe('EnvironmentValidator production launch gate', () => {
|
||||
expect.stringContaining('requires OPERATOR_NAME=Such Software'),
|
||||
expect.stringContaining('requires OPERATOR_CONTACT_URL=mailto:apps@such.software'),
|
||||
expect.stringContaining('requires MONERO_NETWORK=stagenet'),
|
||||
expect.stringContaining('requires PAYMENT_MODES=direct'),
|
||||
expect.stringContaining('requires CREDITS_ENABLED=false'),
|
||||
expect.stringContaining('requires CREDITS_PAYOUTS_ENABLED=false'),
|
||||
expect.stringContaining('requires DIRECT_PAYOUT_ESCAPE=2'),
|
||||
expect.stringContaining('requires SOLO_ENABLED=true'),
|
||||
expect.stringContaining('requires TAVERN_ENABLED=true'),
|
||||
|
||||
@@ -120,16 +120,16 @@ describe('GET /api/leaderboard operated-product integrity', () => {
|
||||
expect(db.calls[0].params.slice(1, 3)).toEqual([['PAID_CREDITS'], true]);
|
||||
});
|
||||
|
||||
test('Monerogue Champions includes direct and credit solo, never match-generated rows', async () => {
|
||||
test('Monerogue Champions includes direct solo only, never historical credit or match rows', async () => {
|
||||
const { response, db } = await invokeLeaderboardRoute('such-monerogue-stagenet', {
|
||||
board: 'champions',
|
||||
period: 'all'
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.leaderboard.map(row => row.name))
|
||||
.toEqual(['CreditSolo', 'LegacyDirect']);
|
||||
.toEqual(['LegacyDirect']);
|
||||
expect(db.calls[0].params.slice(1, 3))
|
||||
.toEqual([['PAID_SINGLE', 'PAID_CREDITS'], true]);
|
||||
.toEqual([['PAID_SINGLE'], true]);
|
||||
});
|
||||
|
||||
test('independent deployments retain the generic opt-in crypto-match mapping', async () => {
|
||||
|
||||
@@ -82,6 +82,7 @@ describe('production disclosure pages', () => {
|
||||
currencyLabel: 'sXMR',
|
||||
network: 'stagenet',
|
||||
isTestNetwork: true,
|
||||
creditsModeEnabled: false,
|
||||
payoutsEnabled: true,
|
||||
isPayoutEnabledForMode: () => true
|
||||
}));
|
||||
@@ -98,11 +99,13 @@ describe('production disclosure pages', () => {
|
||||
currencyLabel: 'sXMR',
|
||||
network: 'stagenet',
|
||||
isTestNetwork: true,
|
||||
creditsModeEnabled: false,
|
||||
payoutsEnabled: true,
|
||||
isPayoutEnabledForMode: () => true
|
||||
}));
|
||||
expect(terms).toContain('PAID_SINGLE and PAID_CREDITS solo runs use the Hall of Champions');
|
||||
expect(terms).toContain('match-generated game rows are excluded');
|
||||
expect(terms).toContain('Only PAID_SINGLE solo runs use the Hall of Champions');
|
||||
expect(terms).toContain('historical PAID_CREDITS runs and match-generated game rows are excluded');
|
||||
expect(terms).toContain('does not sell credits');
|
||||
expect(terms).toContain('does not offer crypto_race');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ describe('operated product environment templates', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
test('monerogue.app is exactly stagenet 2x/3x solo testing with crypto-match payouts off', () => {
|
||||
test('monerogue.app is exactly direct-only stagenet 2x/3x solo testing', () => {
|
||||
const env = parseExample('.env.stagenet.example');
|
||||
|
||||
expect(env).toEqual(expect.objectContaining({
|
||||
@@ -78,14 +78,14 @@ describe('operated product environment templates', () => {
|
||||
CRYPTO_TYPE: 'XMR',
|
||||
MONERO_NETWORK: 'stagenet',
|
||||
FREE_PLAY_ENABLED: 'true',
|
||||
PAYMENT_MODES: 'direct,credits',
|
||||
PAYMENT_MODES: 'direct',
|
||||
DIRECT_PAYMENT_ENABLED: 'true',
|
||||
CREDITS_ENABLED: 'false',
|
||||
PAYOUTS_ENABLED: 'true',
|
||||
DIRECT_PAYOUTS_ENABLED: 'true',
|
||||
CREDITS_PAYOUTS_ENABLED: 'true',
|
||||
CREDITS_PAYOUTS_ENABLED: 'false',
|
||||
DIRECT_PAYOUT_ESCAPE: '2.0',
|
||||
DIRECT_PAYOUT_TREASURE: '3.0',
|
||||
CREDITS_PAYOUT_ESCAPE: '2.0',
|
||||
CREDITS_PAYOUT_TREASURE: '3.0',
|
||||
ALLOW_MAINNET_PAYOUTS: 'false',
|
||||
SOLO_ENABLED: 'true',
|
||||
TAVERN_ENABLED: 'true',
|
||||
@@ -96,9 +96,6 @@ describe('operated product environment templates', () => {
|
||||
expect(BigInt(env.PAYOUT_MAX_PER_GAME)).toBeGreaterThanOrEqual(
|
||||
3n * BigInt(env.DIRECT_GAME_PRICE)
|
||||
);
|
||||
expect(BigInt(env.PAYOUT_MAX_PER_GAME)).toBeGreaterThanOrEqual(
|
||||
3n * BigInt(env.CREDITS_PAYOUT_BASE)
|
||||
);
|
||||
expect(env.COSMETIC_PRODUCTS).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -109,7 +106,7 @@ describe('operated product environment templates', () => {
|
||||
|
||||
test.each([
|
||||
['.env.mainnet.example', 'paid modes: credits'],
|
||||
['.env.stagenet.example', 'paid modes: direct, credits']
|
||||
['.env.stagenet.example', 'paid modes: direct']
|
||||
])('%s passes the real production preflight after only secret substitution', (name, summary) => {
|
||||
const result = preflightExample(name);
|
||||
expect({ status: result.status, stderr: result.stderr }).toEqual({ status: 0, stderr: '' });
|
||||
|
||||
@@ -43,7 +43,7 @@ describe('prestige leaderboard periods', () => {
|
||||
excludeMatchGenerated: true
|
||||
});
|
||||
expect(soloLeaderboardPolicy('such-monerogue-stagenet', 'champions')).toEqual({
|
||||
gameModes: ['PAID_SINGLE', 'PAID_CREDITS'],
|
||||
gameModes: ['PAID_SINGLE'],
|
||||
excludeMatchGenerated: true
|
||||
});
|
||||
expect(soloLeaderboardPolicy(null, 'champions')).toEqual({
|
||||
|
||||
@@ -62,21 +62,21 @@ function visibleState({ player, exit, treasure }) {
|
||||
|
||||
describe('XMR stagenet financial canary safety contract', () => {
|
||||
test('recognizes only the two explicit financial scenarios', () => {
|
||||
expect(Object.keys(SCENARIOS)).toEqual(['direct-2x', 'credits-3x']);
|
||||
expect(Object.keys(SCENARIOS)).toEqual(['direct-2x', 'direct-3x']);
|
||||
expect(SCENARIOS['direct-2x']).toEqual(expect.objectContaining({
|
||||
paymentType: 'single_game',
|
||||
gameMode: 'PAID_SINGLE',
|
||||
multiplier: 2,
|
||||
collectTreasure: false
|
||||
}));
|
||||
expect(SCENARIOS['credits-3x']).toEqual(expect.objectContaining({
|
||||
paymentType: 'credits_package',
|
||||
gameMode: 'PAID_CREDITS',
|
||||
expect(SCENARIOS['direct-3x']).toEqual(expect.objectContaining({
|
||||
paymentType: 'single_game',
|
||||
gameMode: 'PAID_SINGLE',
|
||||
multiplier: 3,
|
||||
collectTreasure: true
|
||||
}));
|
||||
expect(() => readConfiguration(configEnv({ E2E_SCENARIO: 'anything-else' })))
|
||||
.toThrow(/direct-2x or credits-3x/);
|
||||
.toThrow(/direct-2x or direct-3x/);
|
||||
});
|
||||
|
||||
test('refuses public targets, embedded credentials, paths, and the wrong port', () => {
|
||||
@@ -96,17 +96,17 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
|
||||
const env = configEnv({
|
||||
E2E_MODE: 'live-stagenet',
|
||||
E2E_SCENARIO: 'credits-3x',
|
||||
E2E_SCENARIO: 'direct-3x',
|
||||
E2E_MAX_TRANSFER_ATOMIC: '500000000000',
|
||||
E2E_CONFIRM: LIVE_CONFIRM,
|
||||
E2E_SCENARIO_CONFIRM: SCENARIOS['credits-3x'].scenarioConfirm,
|
||||
E2E_SCENARIO_CONFIRM: SCENARIOS['direct-3x'].scenarioConfirm,
|
||||
E2E_CANARY_PROFILE: SAFE_PROFILE_CONFIRM,
|
||||
E2E_DATABASE_NONCE_FILE: '/run/credentials/canary/database-nonce'
|
||||
});
|
||||
const config = readConfiguration(env);
|
||||
expect(() => assertLiveSafety(config, env)).not.toThrow();
|
||||
expect(() => assertLiveSafety(config, { ...env, E2E_SCENARIO_CONFIRM: 'DIRECT_2X_ESCAPE' }))
|
||||
.toThrow(/CREDITS_PACKAGE_THEN_3X/);
|
||||
.toThrow(/DIRECT_3X_TREASURE_ESCAPE/);
|
||||
expect(() => assertLiveSafety(config, { ...env, E2E_CONFIRM: '' }))
|
||||
.toThrow(/E2E_CONFIRM/);
|
||||
const noNonceConfig = readConfiguration({ ...env, E2E_DATABASE_NONCE_FILE: '' });
|
||||
@@ -131,7 +131,7 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
isTestNetwork: true,
|
||||
paymentsEnabled: true,
|
||||
directPaidEntryEnabled: true,
|
||||
paidCreditsEnabled: true,
|
||||
paidCreditsEnabled: false,
|
||||
soloPayoutsEnabled: true,
|
||||
anyPayoutsEnabled: true,
|
||||
paidPrestigeOnly: false,
|
||||
@@ -151,7 +151,7 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
expect(() => canonicalAcknowledgement({
|
||||
...disclosure,
|
||||
service: { ...disclosure.service, cryptoMatchPayoutsEnabled: true }
|
||||
})).toThrow(/payout-enabled paid solo modes/);
|
||||
})).toThrow(/direct-only payout-enabled solo play/);
|
||||
expect(() => canonicalAcknowledgement({
|
||||
...disclosure,
|
||||
operatedProduct: { ...disclosure.operatedProduct, id: 'unreviewed-profile' }
|
||||
@@ -166,7 +166,7 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
isTestNetwork: false,
|
||||
paymentsEnabled: true,
|
||||
directPaidEntryEnabled: true,
|
||||
paidCreditsEnabled: true,
|
||||
paidCreditsEnabled: false,
|
||||
soloPayoutsEnabled: true,
|
||||
anyPayoutsEnabled: true,
|
||||
paidPrestigeOnly: false,
|
||||
@@ -186,8 +186,8 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
payoutMultiplier: { escape: 2, escapeWithTreasure: 3 }
|
||||
},
|
||||
PAID_CREDITS: {
|
||||
enabled: true,
|
||||
payoutMultiplier: { escape: 2, escapeWithTreasure: 3 }
|
||||
enabled: false,
|
||||
payoutMultiplier: 0
|
||||
},
|
||||
match: {
|
||||
enabled: true,
|
||||
@@ -237,6 +237,13 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
...modes,
|
||||
PAID_CREDITS: {
|
||||
...modes.PAID_CREDITS,
|
||||
enabled: true
|
||||
}
|
||||
})).toThrow(/purchased-credit solo/);
|
||||
expect(() => assertPublicModeContract({
|
||||
...modes,
|
||||
PAID_SINGLE: {
|
||||
...modes.PAID_SINGLE,
|
||||
payoutMultiplier: { escape: 2, escapeWithTreasure: 4 }
|
||||
}
|
||||
})).toThrow(/not exactly 3x/);
|
||||
@@ -252,12 +259,12 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
'monerogue_canary_direct_e2e', SCENARIOS['direct-2x']
|
||||
)).not.toThrow();
|
||||
expect(() => validateExpectedDatabaseName(
|
||||
'monerogue_canary_credits_e2e', SCENARIOS['credits-3x']
|
||||
'monerogue_canary_treasure_e2e', SCENARIOS['direct-3x']
|
||||
)).not.toThrow();
|
||||
expect(() => validateExpectedDatabaseName('monerogue', SCENARIOS['direct-2x']))
|
||||
.toThrow(/canary and e2e/);
|
||||
expect(() => validateExpectedDatabaseName(
|
||||
'monerogue_canary_credits_e2e', SCENARIOS['direct-2x']
|
||||
'monerogue_canary_treasure_e2e', SCENARIOS['direct-2x']
|
||||
)).toThrow(/scenario tag/);
|
||||
});
|
||||
|
||||
@@ -358,7 +365,7 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
.toThrow(/could not prove/);
|
||||
});
|
||||
|
||||
test('direct bot avoids treasure while credits bot gets treasure before exit', () => {
|
||||
test('2x direct bot avoids treasure while 3x direct bot gets treasure before exit', () => {
|
||||
const directState = visibleState({
|
||||
player: { x: 0, y: 0, hasTreasure: false },
|
||||
treasure: [1, 0],
|
||||
@@ -369,28 +376,28 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
expect(chooseMove(directKnown, directState, botState(), SCENARIOS['direct-2x']))
|
||||
.toBe('down');
|
||||
|
||||
const creditsState = visibleState({
|
||||
const treasureState = visibleState({
|
||||
player: { x: 0, y: 0, hasTreasure: false },
|
||||
treasure: [1, 0],
|
||||
exit: [2, 0]
|
||||
});
|
||||
const creditsKnown = new Map();
|
||||
addVisible(creditsKnown, creditsState);
|
||||
const creditsBot = botState();
|
||||
expect(chooseMove(creditsKnown, creditsState, creditsBot, SCENARIOS['credits-3x']))
|
||||
const treasureKnown = new Map();
|
||||
addVisible(treasureKnown, treasureState);
|
||||
const treasureBot = botState();
|
||||
expect(chooseMove(treasureKnown, treasureState, treasureBot, SCENARIOS['direct-3x']))
|
||||
.toBe('right');
|
||||
const collected = {
|
||||
...creditsState,
|
||||
...treasureState,
|
||||
player: { x: 1, y: 0, hasTreasure: true },
|
||||
treasure: null
|
||||
};
|
||||
expect(chooseMove(creditsKnown, collected, creditsBot, SCENARIOS['credits-3x']))
|
||||
expect(chooseMove(treasureKnown, collected, treasureBot, SCENARIOS['direct-3x']))
|
||||
.toBe('right');
|
||||
});
|
||||
|
||||
test.each([
|
||||
['direct-2x', 10n, false],
|
||||
['credits-3x', 7n, true]
|
||||
['direct-3x', 7n, true]
|
||||
])('verifies exact game-over liability and two-party proof for %s', (scenarioName, base, treasure) => {
|
||||
const scenario = SCENARIOS[scenarioName];
|
||||
const serverSeed = '11'.repeat(32);
|
||||
@@ -452,14 +459,14 @@ describe('XMR stagenet financial canary safety contract', () => {
|
||||
expect(safe).not.toContain('password@example');
|
||||
});
|
||||
|
||||
test('source has one non-retriable relay call, a guarded main, and both exact flows', () => {
|
||||
test('source has one non-retriable relay call, a guarded main, and direct-only entry', () => {
|
||||
const source = fs.readFileSync(SCRIPT, 'utf8');
|
||||
expect((source.match(/funding\.rpc\('transfer'/g) || [])).toHaveLength(1);
|
||||
expect(source).toMatch(/transferGate\.attempted = true;[\s\S]*do_not_relay: false/);
|
||||
expect(source).toContain('if (require.main === module)');
|
||||
expect(source).toContain("type: 'single_game'");
|
||||
expect(source).toContain("type: 'credits_package'");
|
||||
expect(source).toContain("socket.emit('auto_start'");
|
||||
expect(source).not.toContain("type: 'credits_package'");
|
||||
expect(source).not.toContain("socket.emit('auto_start'");
|
||||
expect(source).toContain('legalAcknowledgement: acknowledgement');
|
||||
expect(source).not.toContain('console.log(');
|
||||
const mainBody = source.slice(source.indexOf('async function main('));
|
||||
|
||||
Reference in New Issue
Block a user