@moneypot/hub 1.18.0-dev.1 → 1.18.0-dev.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/custom-game-config.d.ts +7 -0
- package/dist/src/custom-game-config.js +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +6 -2
- package/dist/src/plugins/hub-make-outcome-bet.d.ts +4 -4
- package/dist/src/plugins/hub-make-outcome-bet.js +11 -70
- package/dist/src/plugins/hub-risk-limits.d.ts +6 -0
- package/dist/src/plugins/hub-risk-limits.js +124 -0
- package/dist/src/process-withdrawal-request.d.ts +1 -7
- package/dist/src/process-withdrawal-request.js +1 -146
- package/dist/src/risk-policy.d.ts +0 -1
- package/dist/src/risk-policy.js +0 -15
- package/dist/src/server/index.d.ts +5 -2
- package/dist/src/server/index.js +6 -3
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/src/index.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ declare global {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig, } from "./plugins/hub-make-outcome-bet.js";
|
|
21
|
+
export { HubRiskLimitsPlugin } from "./plugins/hub-risk-limits.js";
|
|
22
|
+
export { type CustomGameConfig, type CustomGameConfigMap, } from "./custom-game-config.js";
|
|
21
23
|
export { validateRisk, type RiskPolicy, type RiskPolicyArgs, type RiskLimits, } from "./risk-policy.js";
|
|
22
24
|
export type PluginContext = Grafast.Context;
|
|
23
25
|
export { defaultPlugins, type PluginIdentity, type UserSessionContext, } from "./server/graphile.config.js";
|
|
@@ -33,6 +35,7 @@ export type ServerOptions = {
|
|
|
33
35
|
userDatabaseMigrationsPath?: string;
|
|
34
36
|
enableChat?: boolean;
|
|
35
37
|
enablePlayground?: boolean;
|
|
38
|
+
port?: number;
|
|
36
39
|
};
|
|
37
40
|
export declare function runMigrations(options: {
|
|
38
41
|
userDatabaseMigrationsPath?: string;
|
package/dist/src/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { join } from "path";
|
|
|
7
7
|
import { logger } from "./logger.js";
|
|
8
8
|
import { createServerContext, closeServerContext, } from "./context.js";
|
|
9
9
|
export { MakeOutcomeBetPlugin, } from "./plugins/hub-make-outcome-bet.js";
|
|
10
|
+
export { HubRiskLimitsPlugin } from "./plugins/hub-risk-limits.js";
|
|
10
11
|
export { validateRisk, } from "./risk-policy.js";
|
|
11
12
|
export { defaultPlugins, } from "./server/graphile.config.js";
|
|
12
13
|
export async function runMigrations(options) {
|
|
@@ -28,6 +29,7 @@ export async function runMigrations(options) {
|
|
|
28
29
|
pgClient,
|
|
29
30
|
dirname: join(import.meta.dirname, "pg-versions"),
|
|
30
31
|
schemaName: "hub_core_versions",
|
|
32
|
+
silent: process.env.NODE_ENV === "test",
|
|
31
33
|
});
|
|
32
34
|
}
|
|
33
35
|
catch (e) {
|
|
@@ -43,6 +45,7 @@ export async function runMigrations(options) {
|
|
|
43
45
|
pgClient,
|
|
44
46
|
dirname: options.userDatabaseMigrationsPath,
|
|
45
47
|
schemaName: "hub_user_versions",
|
|
48
|
+
silent: process.env.NODE_ENV === "test",
|
|
46
49
|
});
|
|
47
50
|
}
|
|
48
51
|
}
|
|
@@ -98,6 +101,7 @@ export async function startAndListen(options) {
|
|
|
98
101
|
context,
|
|
99
102
|
enableChat: options.enableChat ?? true,
|
|
100
103
|
enablePlayground: options.enablePlayground ?? true,
|
|
104
|
+
port: options.port ?? config.PORT,
|
|
101
105
|
});
|
|
102
106
|
const gracefulShutdown = async ({ exit = true } = {}) => {
|
|
103
107
|
if (isShuttingDown) {
|
|
@@ -128,9 +132,9 @@ export async function startAndListen(options) {
|
|
|
128
132
|
process.on("SIGINT", gracefulShutdown);
|
|
129
133
|
process.on("SIGTERM", gracefulShutdown);
|
|
130
134
|
}
|
|
131
|
-
return hubServer.listen().then(() => {
|
|
135
|
+
return hubServer.listen().then(({ port }) => {
|
|
132
136
|
return {
|
|
133
|
-
port
|
|
137
|
+
port,
|
|
134
138
|
stop: async () => {
|
|
135
139
|
await gracefulShutdown({ exit: false });
|
|
136
140
|
},
|
|
@@ -33,10 +33,10 @@ export type OutcomeBetConfig = {
|
|
|
33
33
|
initializeMetadataFromUntrustedUserInput?: (input: Input) => Result<Metadata, string>;
|
|
34
34
|
finalizeMetadata?: (validatedMetadata: Metadata, data: FinalizeMetadataData) => Metadata;
|
|
35
35
|
};
|
|
36
|
-
export type OutcomeBetConfigMap<
|
|
37
|
-
[
|
|
36
|
+
export type OutcomeBetConfigMap<OutcomeBetKind extends string> = {
|
|
37
|
+
[kind in OutcomeBetKind]: OutcomeBetConfig;
|
|
38
38
|
};
|
|
39
|
-
export declare function MakeOutcomeBetPlugin<
|
|
40
|
-
|
|
39
|
+
export declare function MakeOutcomeBetPlugin<OutcomeBetKind extends string>({ outcomeBetConfigs, }: {
|
|
40
|
+
outcomeBetConfigs: OutcomeBetConfigMap<OutcomeBetKind>;
|
|
41
41
|
}): GraphileConfig.Plugin;
|
|
42
42
|
export {};
|
|
@@ -2,7 +2,7 @@ import { access, context, object, ObjectStep, sideEffect, } from "postgraphile/g
|
|
|
2
2
|
import { gql, extendSchema } from "postgraphile/utils";
|
|
3
3
|
import * as z from "zod/v4";
|
|
4
4
|
import { GraphQLError } from "graphql";
|
|
5
|
-
import { DbHashKind,
|
|
5
|
+
import { DbHashKind, dbLockHouseBankroll, dbLockPlayerBalance, exactlyOneRow, maybeOneRow, 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 } from "../hash-chain/get-hash.js";
|
|
@@ -68,18 +68,18 @@ const BetConfigsSchema = z.record(BetKindSchema, z.object({
|
|
|
68
68
|
.function()
|
|
69
69
|
.optional(),
|
|
70
70
|
}));
|
|
71
|
-
export function MakeOutcomeBetPlugin({
|
|
72
|
-
BetConfigsSchema.parse(
|
|
73
|
-
const
|
|
71
|
+
export function MakeOutcomeBetPlugin({ outcomeBetConfigs, }) {
|
|
72
|
+
BetConfigsSchema.parse(outcomeBetConfigs);
|
|
73
|
+
const outcomeBetKinds = Object.keys(outcomeBetConfigs);
|
|
74
74
|
return extendSchema((build) => {
|
|
75
75
|
const outcomeBetTable = build.input.pgRegistry.pgResources.hub_outcome_bet;
|
|
76
76
|
const typeDefs = gql `
|
|
77
|
-
enum
|
|
78
|
-
${
|
|
77
|
+
enum OutcomeBetKind {
|
|
78
|
+
${outcomeBetKinds.join("\n")}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
input HubMakeOutcomeBetInput {
|
|
82
|
-
kind:
|
|
82
|
+
kind: OutcomeBetKind!
|
|
83
83
|
wager: Int!
|
|
84
84
|
currency: String!
|
|
85
85
|
outcomes: [HubOutcomeInput!]!
|
|
@@ -106,58 +106,10 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
106
106
|
extend type Mutation {
|
|
107
107
|
hubMakeOutcomeBet(input: HubMakeOutcomeBetInput!): HubMakeOutcomeBetPayload
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
type HubRiskLimit {
|
|
111
|
-
maxPayout: Float!
|
|
112
|
-
maxWager: Float
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
type HubRiskLimitWithCurrency {
|
|
116
|
-
currency: String!
|
|
117
|
-
maxPayout: Float!
|
|
118
|
-
maxWager: Float
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
extend type Query {
|
|
122
|
-
hubRiskLimits(betKind: BetKind!): [HubRiskLimitWithCurrency!]!
|
|
123
|
-
}
|
|
124
109
|
`;
|
|
125
110
|
return {
|
|
126
111
|
typeDefs,
|
|
127
112
|
objects: {
|
|
128
|
-
Query: {
|
|
129
|
-
plans: {
|
|
130
|
-
hubRiskLimits: (_, { $betKind }) => {
|
|
131
|
-
const $identity = context().get("identity");
|
|
132
|
-
const $superuserPool = context().get("superuserPool");
|
|
133
|
-
const $result = sideEffect([$identity, $superuserPool, $betKind], async ([identity, superuserPool, betKind]) => {
|
|
134
|
-
if (identity?.kind !== "user") {
|
|
135
|
-
throw new GraphQLError("Unauthorized");
|
|
136
|
-
}
|
|
137
|
-
const betConfig = betConfigs[betKind];
|
|
138
|
-
if (!betConfig) {
|
|
139
|
-
throw new GraphQLError(`Invalid bet kind`);
|
|
140
|
-
}
|
|
141
|
-
const dbHouseBankrolls = await dbGetHouseBankrolls(superuserPool, {
|
|
142
|
-
casinoId: identity.session.casino_id,
|
|
143
|
-
});
|
|
144
|
-
const limitsWithCurrency = dbHouseBankrolls.map((bankroll) => {
|
|
145
|
-
const limits = betConfig.riskPolicy({
|
|
146
|
-
type: "get-limits",
|
|
147
|
-
currency: bankroll.currency_key,
|
|
148
|
-
bankroll: bankroll.amount,
|
|
149
|
-
});
|
|
150
|
-
return {
|
|
151
|
-
currency: bankroll.currency_key,
|
|
152
|
-
...limits,
|
|
153
|
-
};
|
|
154
|
-
});
|
|
155
|
-
return limitsWithCurrency;
|
|
156
|
-
});
|
|
157
|
-
return $result;
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
113
|
Mutation: {
|
|
162
114
|
plans: {
|
|
163
115
|
hubMakeOutcomeBet: (_, { $input }) => {
|
|
@@ -168,10 +120,10 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
168
120
|
throw new GraphQLError("Unauthorized");
|
|
169
121
|
}
|
|
170
122
|
let input;
|
|
171
|
-
let
|
|
123
|
+
let outcomeBetKind;
|
|
172
124
|
try {
|
|
173
125
|
input = InputSchema.parse(rawInput);
|
|
174
|
-
|
|
126
|
+
outcomeBetKind = BetKindSchema.parse(rawInput.kind);
|
|
175
127
|
}
|
|
176
128
|
catch (e) {
|
|
177
129
|
if (e instanceof z.ZodError) {
|
|
@@ -183,9 +135,9 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
183
135
|
input.currency !== "HOUSE") {
|
|
184
136
|
throw new GraphQLError("Playground users can only bet with HOUSE currency");
|
|
185
137
|
}
|
|
186
|
-
const betConfig =
|
|
138
|
+
const betConfig = outcomeBetConfigs[outcomeBetKind];
|
|
187
139
|
if (!betConfig) {
|
|
188
|
-
throw new GraphQLError(`Invalid bet kind`);
|
|
140
|
+
throw new GraphQLError(`Invalid outcome bet kind`);
|
|
189
141
|
}
|
|
190
142
|
if (!betConfig.allowLossBeyondWager) {
|
|
191
143
|
const minProfit = Math.min(...input.outcomes.map((o) => o.profit));
|
|
@@ -496,17 +448,6 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
496
448
|
},
|
|
497
449
|
},
|
|
498
450
|
},
|
|
499
|
-
HubRiskLimit: {
|
|
500
|
-
assertStep: ObjectStep,
|
|
501
|
-
plans: {
|
|
502
|
-
maxWager($data) {
|
|
503
|
-
return access($data, "maxWager");
|
|
504
|
-
},
|
|
505
|
-
maxPayout($data) {
|
|
506
|
-
return access($data, "maxPayout");
|
|
507
|
-
},
|
|
508
|
-
},
|
|
509
|
-
},
|
|
510
451
|
HubMakeOutcomeBetPayload: {
|
|
511
452
|
assertStep: ObjectStep,
|
|
512
453
|
plans: {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { OutcomeBetConfigMap } from "./hub-make-outcome-bet.js";
|
|
2
|
+
import { CustomGameConfigMap } from "../custom-game-config.js";
|
|
3
|
+
export declare function HubRiskLimitsPlugin<OutcomeBetKind extends string, CustomGameKind extends string = never>({ outcomeBetConfigs, customGameConfigs, }: {
|
|
4
|
+
outcomeBetConfigs: OutcomeBetConfigMap<OutcomeBetKind>;
|
|
5
|
+
customGameConfigs?: CustomGameConfigMap<CustomGameKind>;
|
|
6
|
+
}): GraphileConfig.Plugin;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { context, sideEffect, access } from "postgraphile/grafast";
|
|
2
|
+
import { gql, extendSchema } from "postgraphile/utils";
|
|
3
|
+
import { GraphQLError } from "graphql";
|
|
4
|
+
import { dbGetHouseBankrolls } from "../db/index.js";
|
|
5
|
+
export function HubRiskLimitsPlugin({ outcomeBetConfigs, customGameConfigs, }) {
|
|
6
|
+
const outcomeBetKinds = Object.keys(outcomeBetConfigs);
|
|
7
|
+
const customGameKinds = customGameConfigs
|
|
8
|
+
? Object.keys(customGameConfigs)
|
|
9
|
+
: [];
|
|
10
|
+
if (customGameConfigs) {
|
|
11
|
+
const outcomeBetKindSet = new Set(outcomeBetKinds);
|
|
12
|
+
for (const kind of customGameKinds) {
|
|
13
|
+
if (outcomeBetKindSet.has(kind)) {
|
|
14
|
+
throw new Error(`Key collision: "${kind}" exists in both outcomeBetConfigs and customGameConfigs`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const anyGameKinds = [...outcomeBetKinds, ...customGameKinds];
|
|
19
|
+
const mergedConfigs = {};
|
|
20
|
+
for (const kind of outcomeBetKinds) {
|
|
21
|
+
mergedConfigs[kind] = outcomeBetConfigs[kind];
|
|
22
|
+
}
|
|
23
|
+
if (customGameConfigs) {
|
|
24
|
+
for (const kind of customGameKinds) {
|
|
25
|
+
mergedConfigs[kind] = customGameConfigs[kind];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return extendSchema((build) => {
|
|
29
|
+
const typeDefs = gql `
|
|
30
|
+
enum AnyGameKind {
|
|
31
|
+
${anyGameKinds.join("\n")}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
${customGameKinds.length > 0
|
|
35
|
+
? `enum CustomGameKind {
|
|
36
|
+
${customGameKinds.join("\n")}
|
|
37
|
+
}`
|
|
38
|
+
: ""}
|
|
39
|
+
|
|
40
|
+
type HubRiskLimit {
|
|
41
|
+
maxPayout: Float!
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type HubBulkRiskLimit {
|
|
45
|
+
gameKind: AnyGameKind!
|
|
46
|
+
currency: String!
|
|
47
|
+
maxPayout: Float!
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
extend type Query {
|
|
51
|
+
hubRiskLimits(gameKinds: [AnyGameKind!]!): [HubBulkRiskLimit!]!
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
return {
|
|
55
|
+
typeDefs,
|
|
56
|
+
objects: {
|
|
57
|
+
Query: {
|
|
58
|
+
plans: {
|
|
59
|
+
hubRiskLimits: (_, { $gameKinds }) => {
|
|
60
|
+
const $identity = context().get("identity");
|
|
61
|
+
const $superuserPool = context().get("superuserPool");
|
|
62
|
+
const $result = sideEffect([$identity, $superuserPool, $gameKinds], async ([identity, superuserPool, inputGameKinds]) => {
|
|
63
|
+
if (identity?.kind !== "user") {
|
|
64
|
+
throw new GraphQLError("Unauthorized");
|
|
65
|
+
}
|
|
66
|
+
if (inputGameKinds.length > 10) {
|
|
67
|
+
throw new GraphQLError("Maximum 10 game kinds allowed");
|
|
68
|
+
}
|
|
69
|
+
if (new Set(inputGameKinds).size !== inputGameKinds.length) {
|
|
70
|
+
throw new GraphQLError("Duplicate game kinds not allowed");
|
|
71
|
+
}
|
|
72
|
+
for (const kind of inputGameKinds) {
|
|
73
|
+
if (!mergedConfigs[kind]) {
|
|
74
|
+
throw new GraphQLError(`Invalid game kind: ${kind}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const dbHouseBankrolls = await dbGetHouseBankrolls(superuserPool, {
|
|
78
|
+
casinoId: identity.session.casino_id,
|
|
79
|
+
});
|
|
80
|
+
const limits = inputGameKinds.flatMap((gameKind) => {
|
|
81
|
+
const config = mergedConfigs[gameKind];
|
|
82
|
+
return dbHouseBankrolls.map((bankroll) => {
|
|
83
|
+
const riskLimits = config.riskPolicy({
|
|
84
|
+
type: "get-limits",
|
|
85
|
+
currency: bankroll.currency_key,
|
|
86
|
+
bankroll: bankroll.amount,
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
gameKind,
|
|
90
|
+
currency: bankroll.currency_key,
|
|
91
|
+
maxPayout: riskLimits.maxPayout,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
return limits;
|
|
96
|
+
});
|
|
97
|
+
return $result;
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
HubRiskLimit: {
|
|
102
|
+
plans: {
|
|
103
|
+
maxPayout($data) {
|
|
104
|
+
return access($data, "maxPayout");
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
HubBulkRiskLimit: {
|
|
109
|
+
plans: {
|
|
110
|
+
gameKind($data) {
|
|
111
|
+
return access($data, "gameKind");
|
|
112
|
+
},
|
|
113
|
+
currency($data) {
|
|
114
|
+
return access($data, "currency");
|
|
115
|
+
},
|
|
116
|
+
maxPayout($data) {
|
|
117
|
+
return access($data, "maxPayout");
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}, "HubRiskLimitsPlugin");
|
|
124
|
+
}
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { GraphQLClient } from "graphql-request";
|
|
3
|
-
export declare function processWithdrawalRequests({ casinoId, graphqlClient, pool, }: {
|
|
4
|
-
casinoId: string;
|
|
5
|
-
graphqlClient: GraphQLClient;
|
|
6
|
-
pool: pg.Pool;
|
|
7
|
-
}): Promise<void>;
|
|
1
|
+
export {};
|
|
@@ -1,146 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { TransferStatusKind } from "./__generated__/graphql.js";
|
|
3
|
-
import { withPgPoolTransaction } from "./db/index.js";
|
|
4
|
-
import { maybeOneRow, exactlyOneRow } from "./db/util.js";
|
|
5
|
-
import { START_PENDING_EXPERIENCE_TRANSFER } from "./graphql-queries.js";
|
|
6
|
-
import { logger } from "./logger.js";
|
|
7
|
-
async function processWithdrawalRequest({ requestId, graphqlClient, pool, }) {
|
|
8
|
-
return withPgPoolTransaction(pool, async (pgClient) => {
|
|
9
|
-
const dbWithdrawalRequest = await pgClient
|
|
10
|
-
.query({
|
|
11
|
-
text: `
|
|
12
|
-
select *
|
|
13
|
-
from hub.withdrawal_request
|
|
14
|
-
where id = $1
|
|
15
|
-
|
|
16
|
-
FOR UPDATE
|
|
17
|
-
`,
|
|
18
|
-
values: [requestId],
|
|
19
|
-
})
|
|
20
|
-
.then(maybeOneRow);
|
|
21
|
-
if (!dbWithdrawalRequest) {
|
|
22
|
-
throw new Error("Withdrawal request not found");
|
|
23
|
-
}
|
|
24
|
-
if (dbWithdrawalRequest.mp_transfer_id) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const dbUser = await pgClient
|
|
28
|
-
.query({
|
|
29
|
-
text: `select * from hub.user where id = $1`,
|
|
30
|
-
values: [dbWithdrawalRequest.user_id],
|
|
31
|
-
})
|
|
32
|
-
.then(exactlyOneRow);
|
|
33
|
-
const dbExperience = await pgClient
|
|
34
|
-
.query({
|
|
35
|
-
text: `select * from hub.experience where id = $1`,
|
|
36
|
-
values: [dbWithdrawalRequest.experience_id],
|
|
37
|
-
})
|
|
38
|
-
.then(exactlyOneRow);
|
|
39
|
-
const mpResult = await graphqlClient
|
|
40
|
-
.request({
|
|
41
|
-
document: START_PENDING_EXPERIENCE_TRANSFER,
|
|
42
|
-
variables: {
|
|
43
|
-
mpUserId: dbUser.mp_user_id,
|
|
44
|
-
mpExperienceId: dbExperience.mp_experience_id,
|
|
45
|
-
amount: dbWithdrawalRequest.amount,
|
|
46
|
-
currency: dbWithdrawalRequest.currency_key,
|
|
47
|
-
metadata: JSON.stringify({
|
|
48
|
-
id: `withdrawal_request:${dbWithdrawalRequest.id}`,
|
|
49
|
-
}),
|
|
50
|
-
},
|
|
51
|
-
})
|
|
52
|
-
.then((res) => res.transferCurrencyExperienceToUser?.result);
|
|
53
|
-
if (!mpResult?.__typename) {
|
|
54
|
-
throw new Error(`Failed to start MP transfer: ${mpResult}`);
|
|
55
|
-
}
|
|
56
|
-
if (mpResult.__typename === "TakeRequestAlreadyTerminal") {
|
|
57
|
-
if (mpResult.takeRequest.experienceTransfer) {
|
|
58
|
-
const mpTransferId = mpResult.takeRequest.experienceTransfer.id;
|
|
59
|
-
await pgClient.query({
|
|
60
|
-
text: `
|
|
61
|
-
update hub.withdrawal_request
|
|
62
|
-
set mp_transfer_id = $2
|
|
63
|
-
where id = $1
|
|
64
|
-
`,
|
|
65
|
-
values: [dbWithdrawalRequest.id, mpTransferId],
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
if (mpResult?.__typename !== "TransferSuccess" &&
|
|
70
|
-
mpResult?.__typename !== "TransferMetadataIdExists") {
|
|
71
|
-
throw new Error(`Failed to start MP transfer: ${mpResult}`);
|
|
72
|
-
}
|
|
73
|
-
const mpTransferId = mpResult.transfer.id;
|
|
74
|
-
const mpStatus = mpResult.transfer.status;
|
|
75
|
-
await pgClient
|
|
76
|
-
.query({
|
|
77
|
-
text: `
|
|
78
|
-
update hub.withdrawal_request
|
|
79
|
-
set mp_transfer_id = $2
|
|
80
|
-
where id = $1
|
|
81
|
-
`,
|
|
82
|
-
values: [dbWithdrawalRequest.id, mpTransferId],
|
|
83
|
-
})
|
|
84
|
-
.then((res) => {
|
|
85
|
-
assert(res.rowCount === 1, `Expected to update a hub.withdrawal_request.mp_transfer_id`);
|
|
86
|
-
});
|
|
87
|
-
if (mpStatus === TransferStatusKind.Pending ||
|
|
88
|
-
mpStatus === TransferStatusKind.Completed) {
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
logger.warn(`Expected status to be PENDING or COMPLETED, but got ${mpStatus}`);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
await pgClient.query({
|
|
95
|
-
text: `
|
|
96
|
-
insert into hub.withdrawal(
|
|
97
|
-
id,
|
|
98
|
-
casino_id,
|
|
99
|
-
mp_transfer_id,
|
|
100
|
-
user_id,
|
|
101
|
-
experience_id,
|
|
102
|
-
amount,
|
|
103
|
-
currency_key,
|
|
104
|
-
status,
|
|
105
|
-
withdrawal_request_id
|
|
106
|
-
)
|
|
107
|
-
values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
108
|
-
`,
|
|
109
|
-
values: [
|
|
110
|
-
dbWithdrawalRequest.id,
|
|
111
|
-
dbWithdrawalRequest.casino_id,
|
|
112
|
-
mpTransferId,
|
|
113
|
-
dbWithdrawalRequest.user_id,
|
|
114
|
-
dbWithdrawalRequest.experience_id,
|
|
115
|
-
dbWithdrawalRequest.amount,
|
|
116
|
-
dbWithdrawalRequest.currency_key,
|
|
117
|
-
mpResult.transfer.status,
|
|
118
|
-
dbWithdrawalRequest.id,
|
|
119
|
-
],
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
export async function processWithdrawalRequests({ casinoId, graphqlClient, pool, }) {
|
|
124
|
-
const pendingRequests = await pool.query({
|
|
125
|
-
text: `
|
|
126
|
-
SELECT wr.*
|
|
127
|
-
FROM hub.withdrawal_request wr
|
|
128
|
-
WHERE wr.casino_id = $1
|
|
129
|
-
AND wr.mp_transfer_id IS NULL
|
|
130
|
-
LIMIT 10
|
|
131
|
-
`,
|
|
132
|
-
values: [casinoId],
|
|
133
|
-
});
|
|
134
|
-
for (const request of pendingRequests.rows) {
|
|
135
|
-
try {
|
|
136
|
-
await processWithdrawalRequest({
|
|
137
|
-
requestId: request.id,
|
|
138
|
-
graphqlClient,
|
|
139
|
-
pool,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
logger.error(error, `Failed to process withdrawal request ${request.id}`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
1
|
+
export {};
|
package/dist/src/risk-policy.js
CHANGED
|
@@ -2,7 +2,6 @@ import { formatCurrency } from "./format-currency.js";
|
|
|
2
2
|
import { z } from "zod/v4";
|
|
3
3
|
const RiskLimitsSchema = z
|
|
4
4
|
.object({
|
|
5
|
-
maxWager: z.number().positive().optional(),
|
|
6
5
|
maxPayout: z.number().positive(),
|
|
7
6
|
})
|
|
8
7
|
.strict();
|
|
@@ -21,20 +20,6 @@ export function validateRisk(options) {
|
|
|
21
20
|
error: { message, riskLimits: options.riskLimits },
|
|
22
21
|
};
|
|
23
22
|
}
|
|
24
|
-
if (options.riskLimits.maxWager !== undefined &&
|
|
25
|
-
wager > options.riskLimits.maxWager) {
|
|
26
|
-
const message = `Wager (${formatCurrency(wager, {
|
|
27
|
-
displayUnitName: options.displayUnitName,
|
|
28
|
-
displayUnitScale: options.displayUnitScale,
|
|
29
|
-
})}) exceeds limit (${formatCurrency(options.riskLimits.maxWager, {
|
|
30
|
-
displayUnitName: options.displayUnitName,
|
|
31
|
-
displayUnitScale: options.displayUnitScale,
|
|
32
|
-
})})`;
|
|
33
|
-
return {
|
|
34
|
-
ok: false,
|
|
35
|
-
error: { message, riskLimits: options.riskLimits },
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
23
|
if (maxPotentialPayout > options.riskLimits.maxPayout) {
|
|
39
24
|
const message = `Payout (${formatCurrency(maxPotentialPayout, {
|
|
40
25
|
displayUnitName: options.displayUnitName,
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { ServerOptions } from "../index.js";
|
|
2
2
|
import { ServerContext } from "../context.js";
|
|
3
3
|
export type HubServer = {
|
|
4
|
-
listen: () => Promise<
|
|
4
|
+
listen: () => Promise<{
|
|
5
|
+
port: number;
|
|
6
|
+
}>;
|
|
5
7
|
shutdown: () => Promise<void>;
|
|
6
8
|
};
|
|
7
|
-
export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
|
|
9
|
+
export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, port, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
|
|
8
10
|
abortSignal: AbortSignal;
|
|
9
11
|
context: ServerContext;
|
|
10
12
|
enableChat: boolean;
|
|
11
13
|
enablePlayground: boolean;
|
|
14
|
+
port: number;
|
|
12
15
|
}): HubServer;
|
package/dist/src/server/index.js
CHANGED
|
@@ -3,7 +3,6 @@ import { grafserv } from "postgraphile/grafserv/express/v4";
|
|
|
3
3
|
import postgraphile from "postgraphile";
|
|
4
4
|
import { createPreset, defaultPlugins } from "./graphile.config.js";
|
|
5
5
|
import express from "express";
|
|
6
|
-
import * as config from "../config.js";
|
|
7
6
|
import { logger } from "../logger.js";
|
|
8
7
|
import cors from "./middleware/cors.js";
|
|
9
8
|
import authentication from "./middleware/authentication.js";
|
|
@@ -45,7 +44,7 @@ function createExpressServer(context) {
|
|
|
45
44
|
});
|
|
46
45
|
return app;
|
|
47
46
|
}
|
|
48
|
-
export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }) {
|
|
47
|
+
export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, port, }) {
|
|
49
48
|
const expressServer = createExpressServer(context);
|
|
50
49
|
const preset = createPreset({
|
|
51
50
|
plugins: plugins ?? defaultPlugins,
|
|
@@ -72,7 +71,11 @@ export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, ex
|
|
|
72
71
|
return {
|
|
73
72
|
listen: () => {
|
|
74
73
|
return new Promise((resolve) => {
|
|
75
|
-
nodeServer.listen(
|
|
74
|
+
nodeServer.listen(port, () => {
|
|
75
|
+
const addr = nodeServer.address();
|
|
76
|
+
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
77
|
+
resolve({ port: actualPort });
|
|
78
|
+
});
|
|
76
79
|
});
|
|
77
80
|
},
|
|
78
81
|
shutdown: () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moneypot/hub",
|
|
3
|
-
"version": "1.18.0-dev.
|
|
3
|
+
"version": "1.18.0-dev.3",
|
|
4
4
|
"author": "moneypot.com",
|
|
5
5
|
"homepage": "https://moneypot.com/hub",
|
|
6
6
|
"keywords": [
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@graphile-contrib/pg-omit-archived": "^4.0.0-beta.4",
|
|
53
53
|
"@moneypot/hash-herald": "^1.0.0",
|
|
54
|
-
"@moneypot/pg-upgrade-schema": "^2.0
|
|
54
|
+
"@moneypot/pg-upgrade-schema": "^2.1.0",
|
|
55
55
|
"@noble/curves": "^1.5.0",
|
|
56
56
|
"dotenv": "^16.4.5",
|
|
57
57
|
"express": "^5.0.1",
|