@moneypot/hub 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/db/public.d.ts
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import * as pg from "pg";
|
|
2
|
-
import { DbCurrency, DbSession } from "./types.js";
|
|
3
|
-
|
|
4
|
-
export declare function
|
|
2
|
+
import { DbBalance, DbBankroll, DbCurrency, DbSession } from "./types.js";
|
|
3
|
+
import { PgClientInTransaction } from "./index.js";
|
|
4
|
+
export declare function dbGetActiveSessionById(pgClient: pg.PoolClient, sessionId: string): Promise<DbSession | undefined>;
|
|
5
|
+
export declare function dbGetCasinoCurrencyByKey(pgClient: pg.PoolClient, { currencyKey, casinoId }: {
|
|
5
6
|
currencyKey: string;
|
|
6
7
|
casinoId: string;
|
|
7
8
|
}): Promise<DbCurrency | undefined>;
|
|
9
|
+
export declare function dbLockPlayerBalanceAndHouseBankroll(pgClient: PgClientInTransaction, { userId, casinoId, experienceId, currencyKey, }: {
|
|
10
|
+
userId: string;
|
|
11
|
+
casinoId: string;
|
|
12
|
+
experienceId: string;
|
|
13
|
+
currencyKey: string;
|
|
14
|
+
}): Promise<{
|
|
15
|
+
found: false;
|
|
16
|
+
dbPlayerBalance: null;
|
|
17
|
+
dbHouseBankroll: null;
|
|
18
|
+
} | {
|
|
19
|
+
found: true;
|
|
20
|
+
dbPlayerBalance: Pick<DbBalance, "id" | "amount">;
|
|
21
|
+
dbHouseBankroll: Pick<DbBankroll, "id" | "amount">;
|
|
22
|
+
}>;
|
package/dist/src/db/public.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { maybeOneRow } from "./util.js";
|
|
2
|
-
|
|
2
|
+
import { assert } from "tsafe";
|
|
3
|
+
export async function dbGetActiveSessionById(pgClient, sessionId) {
|
|
3
4
|
return pgClient
|
|
4
5
|
.query("select * from hub.active_session where id = $1", [
|
|
5
6
|
sessionId,
|
|
6
7
|
])
|
|
7
8
|
.then(maybeOneRow);
|
|
8
9
|
}
|
|
9
|
-
export async function
|
|
10
|
+
export async function dbGetCasinoCurrencyByKey(pgClient, { currencyKey, casinoId }) {
|
|
10
11
|
return pgClient
|
|
11
12
|
.query({
|
|
12
13
|
text: `
|
|
@@ -18,3 +19,40 @@ export async function getCasinoCurrencyByKey(pgClient, { currencyKey, casinoId }
|
|
|
18
19
|
})
|
|
19
20
|
.then(maybeOneRow);
|
|
20
21
|
}
|
|
22
|
+
export async function dbLockPlayerBalanceAndHouseBankroll(pgClient, { userId, casinoId, experienceId, currencyKey, }) {
|
|
23
|
+
assert(pgClient._inTransaction, "pgClient must be in a transaction");
|
|
24
|
+
const row = await pgClient
|
|
25
|
+
.query(`
|
|
26
|
+
WITH locked_balance AS (
|
|
27
|
+
SELECT id, amount
|
|
28
|
+
FROM hub.balance
|
|
29
|
+
WHERE user_id = $1
|
|
30
|
+
AND casino_id = $2
|
|
31
|
+
AND experience_id = $3
|
|
32
|
+
AND currency_key = $4
|
|
33
|
+
|
|
34
|
+
FOR UPDATE
|
|
35
|
+
)
|
|
36
|
+
SELECT
|
|
37
|
+
json_build_object('id', pb.id, 'amount', pb.amount) as player_balance,
|
|
38
|
+
json_build_object('id', br.id, 'amount', br.amount) as house_bankroll
|
|
39
|
+
FROM locked_balance pb
|
|
40
|
+
JOIN hub.bankroll br
|
|
41
|
+
ON br.casino_id = $2
|
|
42
|
+
AND br.currency_key = $4
|
|
43
|
+
|
|
44
|
+
FOR UPDATE OF br
|
|
45
|
+
`, [userId, casinoId, experienceId, currencyKey])
|
|
46
|
+
.then(maybeOneRow);
|
|
47
|
+
return row
|
|
48
|
+
? {
|
|
49
|
+
found: true,
|
|
50
|
+
dbPlayerBalance: row.player_balance,
|
|
51
|
+
dbHouseBankroll: row.house_bankroll,
|
|
52
|
+
}
|
|
53
|
+
: {
|
|
54
|
+
found: false,
|
|
55
|
+
dbPlayerBalance: null,
|
|
56
|
+
dbHouseBankroll: null,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -2,7 +2,7 @@ import { access, context, object, ObjectStep, polymorphicBranch, sideEffect, } f
|
|
|
2
2
|
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { GraphQLError } from "graphql";
|
|
5
|
-
import { DbHashKind, exactlyOneRow, maybeOneRow, superuserPool, withPgPoolTransaction, } from "../db/index.js";
|
|
5
|
+
import { DbHashKind, dbLockPlayerBalanceAndHouseBankroll, exactlyOneRow, maybeOneRow, superuserPool, withPgPoolTransaction, } from "../db/index.js";
|
|
6
6
|
import { assert } from "tsafe";
|
|
7
7
|
import { dbInsertHubHash, dbLockHubHashChain, } from "../hash-chain/db-hash-chain.js";
|
|
8
8
|
import { getIntermediateHash, getPreimageHash, } from "../hash-chain/get-hash.js";
|
|
@@ -150,7 +150,7 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
150
150
|
throw new GraphQLError("Currency not found");
|
|
151
151
|
}
|
|
152
152
|
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
153
|
-
const { dbPlayerBalance, dbHouseBankroll, found } = await
|
|
153
|
+
const { dbPlayerBalance, dbHouseBankroll, found } = await dbLockPlayerBalanceAndHouseBankroll(pgClient, {
|
|
154
154
|
userId: session.user_id,
|
|
155
155
|
casinoId: session.casino_id,
|
|
156
156
|
experienceId: session.experience_id,
|
|
@@ -167,7 +167,7 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
167
167
|
maxPlayerLoss,
|
|
168
168
|
dbPlayerBalance,
|
|
169
169
|
});
|
|
170
|
-
if (dbPlayerBalance < maxPlayerLoss) {
|
|
170
|
+
if (dbPlayerBalance.amount < maxPlayerLoss) {
|
|
171
171
|
if (minProfit === -1) {
|
|
172
172
|
throw new GraphQLError(`You cannot afford wager`);
|
|
173
173
|
}
|
|
@@ -175,7 +175,7 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
175
175
|
}
|
|
176
176
|
const maxProfitMultiplier = Math.max(...input.outcomes.map((o) => o.profit));
|
|
177
177
|
const maxPotentialPayout = input.wager * maxProfitMultiplier;
|
|
178
|
-
const maxAllowablePayout = dbHouseBankroll * 0.01;
|
|
178
|
+
const maxAllowablePayout = dbHouseBankroll.amount * 0.01;
|
|
179
179
|
if (maxPotentialPayout > maxAllowablePayout) {
|
|
180
180
|
throw new GraphQLError(`House risk limit exceeded. Max payout: ${maxPotentialPayout.toFixed(4)}`);
|
|
181
181
|
}
|
|
@@ -409,43 +409,6 @@ function pickRandomOutcome({ outcomes, hash, }) {
|
|
|
409
409
|
outcomeIdx: outcomes.length - 1,
|
|
410
410
|
};
|
|
411
411
|
}
|
|
412
|
-
async function dbLockBalanceAndBankroll(pgClient, { userId, casinoId, experienceId, currencyKey, }) {
|
|
413
|
-
assert(pgClient._inTransaction, "pgClient must be in a transaction");
|
|
414
|
-
const row = await pgClient
|
|
415
|
-
.query(`
|
|
416
|
-
WITH locked_balance AS (
|
|
417
|
-
SELECT amount
|
|
418
|
-
FROM hub.balance
|
|
419
|
-
WHERE user_id = $1
|
|
420
|
-
AND casino_id = $2
|
|
421
|
-
AND experience_id = $3
|
|
422
|
-
AND currency_key = $4
|
|
423
|
-
|
|
424
|
-
FOR UPDATE
|
|
425
|
-
)
|
|
426
|
-
SELECT
|
|
427
|
-
pb.amount as player_balance,
|
|
428
|
-
br.amount as house_bankroll
|
|
429
|
-
FROM locked_balance pb
|
|
430
|
-
JOIN hub.bankroll br
|
|
431
|
-
ON br.casino_id = $2
|
|
432
|
-
AND br.currency_key = $4
|
|
433
|
-
|
|
434
|
-
FOR UPDATE OF br
|
|
435
|
-
`, [userId, casinoId, experienceId, currencyKey])
|
|
436
|
-
.then(maybeOneRow);
|
|
437
|
-
return row
|
|
438
|
-
? {
|
|
439
|
-
found: true,
|
|
440
|
-
dbPlayerBalance: row.player_balance,
|
|
441
|
-
dbHouseBankroll: row.house_bankroll,
|
|
442
|
-
}
|
|
443
|
-
: {
|
|
444
|
-
found: false,
|
|
445
|
-
dbPlayerBalance: null,
|
|
446
|
-
dbHouseBankroll: null,
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
412
|
async function finishHashChainInBackground({ hashChainId, }) {
|
|
450
413
|
console.log("Finishing hash chain in background", { hashChainId });
|
|
451
414
|
const preimageHashResult = await getPreimageHash({
|
|
@@ -29,6 +29,10 @@ export const HubPutAlertPlugin = makeExtendSchemaPlugin(() => {
|
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
31
|
return listenWithFilter($pgSubscriber, $channelKey, jsonParse, $identity, (item, identity) => {
|
|
32
|
+
if (typeof item !== "string") {
|
|
33
|
+
console.warn(`hubPutAlert: item is not a string: ${JSON.stringify(item)}`);
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
32
36
|
if (identity?.kind !== "user") {
|
|
33
37
|
return false;
|
|
34
38
|
}
|
|
@@ -5,7 +5,7 @@ export declare class ListenWithFilterStep<TTopics extends {
|
|
|
5
5
|
[topic: string]: any;
|
|
6
6
|
}, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput> extends Step<TTopics[TTopic][]> {
|
|
7
7
|
itemPlan: (itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep;
|
|
8
|
-
filterFn: (item:
|
|
8
|
+
filterFn: (item: unknown, filterInput: TFilterInput) => boolean;
|
|
9
9
|
static $$export: {
|
|
10
10
|
moduleName: string;
|
|
11
11
|
exportName: string;
|
|
@@ -14,9 +14,9 @@ export declare class ListenWithFilterStep<TTopics extends {
|
|
|
14
14
|
private pubsubDep;
|
|
15
15
|
private topicDep;
|
|
16
16
|
private filterInputDep;
|
|
17
|
-
constructor(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item:
|
|
17
|
+
constructor(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: unknown, filterInput: TFilterInput) => boolean);
|
|
18
18
|
execute({ indexMap, values, stream, }: ExecutionDetails<readonly [GrafastSubscriber<TTopics>, TTopic]>): GrafastResultStreamList<TTopics[TTopic]>;
|
|
19
19
|
}
|
|
20
20
|
export declare function listenWithFilter<TTopics extends {
|
|
21
21
|
[topic: string]: any;
|
|
22
|
-
}, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput>(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item:
|
|
22
|
+
}, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput>(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: unknown, filterInput: TFilterInput) => boolean): ListenWithFilterStep<TTopics, TTopic, TPayloadStep, TFilterInput>;
|