@moneypot/hub 1.2.6 → 1.3.0-dev.1
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/README.md +4 -0
- package/dist/dashboard/assets/index-DuFZbLfp.js +360 -0
- package/dist/dashboard/assets/index-LZVcTrKv.css +5 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/src/db/index.d.ts +15 -15
- package/dist/src/db/index.js +46 -47
- package/dist/src/db/internal.d.ts +5 -4
- package/dist/src/db/internal.js +12 -9
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +4 -0
- package/dist/src/pg-versions/005-outcome-bet.sql +56 -0
- package/dist/src/plugins/hub-claim-faucet.js +3 -1
- package/dist/src/plugins/hub-make-outcome-bet.d.ts +57 -0
- package/dist/src/plugins/hub-make-outcome-bet.js +325 -0
- package/package.json +2 -2
- package/dist/dashboard/assets/index-BhzBHOZb.js +0 -360
- package/dist/dashboard/assets/index-tK7EUtyc.css +0 -5
package/dist/src/db/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as pg from "pg";
|
|
2
2
|
import stream from "node:stream";
|
|
3
3
|
import { DbCasino, DbExperience, DbSession, DbTransferStatusKind, DbUser, DbWithdrawal } from "./types.js";
|
|
4
4
|
import { TransferStatusKind } from "../__generated__/graphql.js";
|
|
5
5
|
export * from "./types.js";
|
|
6
6
|
export * from "./public.js";
|
|
7
7
|
export * from "./util.js";
|
|
8
|
-
export declare function getPgClient(connectionString: string): pg.Client
|
|
8
|
+
export declare function getPgClient(connectionString: string): InstanceType<typeof pg.Client>;
|
|
9
9
|
export declare const postgraphilePool: pg.Pool;
|
|
10
10
|
export declare const superuserPool: pg.Pool;
|
|
11
11
|
export interface QueryExecutor {
|
|
12
|
-
query<T extends QueryResultRow = any>(queryText: string, values?: any[]): Promise<QueryResult<T>>;
|
|
12
|
+
query<T extends pg.QueryResultRow = any>(queryText: string, values?: any[]): Promise<pg.QueryResult<T>>;
|
|
13
13
|
}
|
|
14
14
|
export declare class UserFriendlyError extends Error {
|
|
15
15
|
constructor(userFriendlyMessage: string);
|
|
@@ -17,36 +17,36 @@ export declare class UserFriendlyError extends Error {
|
|
|
17
17
|
export type PgClientInTransaction = pg.PoolClient & {
|
|
18
18
|
_inTransaction: true;
|
|
19
19
|
};
|
|
20
|
-
export declare function withPgPoolTransaction<T>(pool: pg.Pool
|
|
21
|
-
export declare function userFromActiveSessionKey(
|
|
20
|
+
export declare function withPgPoolTransaction<T>(pool: InstanceType<typeof pg.Pool>, callback: (_pgClient: PgClientInTransaction) => Promise<T>, retryCount?: number, maxRetries?: number): Promise<T>;
|
|
21
|
+
export declare function userFromActiveSessionKey(pgClient: QueryExecutor, sessionKey: string): Promise<{
|
|
22
22
|
user: DbUser;
|
|
23
23
|
sessionId: DbSession["id"];
|
|
24
24
|
} | null>;
|
|
25
25
|
declare class DatabaseNotifier extends stream.EventEmitter {
|
|
26
|
-
private
|
|
26
|
+
private pgClient;
|
|
27
27
|
constructor(connectionString: string);
|
|
28
28
|
close(): Promise<void>;
|
|
29
29
|
listen(): Promise<void>;
|
|
30
30
|
}
|
|
31
31
|
export declare const notifier: DatabaseNotifier;
|
|
32
|
-
export declare function getTransferCursor(
|
|
32
|
+
export declare function getTransferCursor(pgClient: QueryExecutor, { casinoId, }: {
|
|
33
33
|
casinoId: string;
|
|
34
34
|
}): Promise<string | undefined>;
|
|
35
|
-
export declare function setTransferCursor(
|
|
35
|
+
export declare function setTransferCursor(pgClient: QueryExecutor, { cursor, casinoId, }: {
|
|
36
36
|
casinoId: string;
|
|
37
37
|
cursor: string;
|
|
38
38
|
}): Promise<void>;
|
|
39
|
-
export declare function upsertUser(
|
|
39
|
+
export declare function upsertUser(pgClient: QueryExecutor, { uname, casinoId, mpUserId, }: {
|
|
40
40
|
uname: string;
|
|
41
41
|
casinoId: string;
|
|
42
42
|
mpUserId: string;
|
|
43
43
|
}): Promise<DbUser>;
|
|
44
|
-
export declare function upsertExperience(
|
|
44
|
+
export declare function upsertExperience(pgClient: QueryExecutor, { casinoId, mpExperienceId, name, }: {
|
|
45
45
|
casinoId: string;
|
|
46
46
|
mpExperienceId: string;
|
|
47
47
|
name: string;
|
|
48
48
|
}): Promise<DbExperience>;
|
|
49
|
-
export declare function insertDeposit(pool: pg.Pool
|
|
49
|
+
export declare function insertDeposit(pool: InstanceType<typeof pg.Pool>, o: {
|
|
50
50
|
casinoId: string;
|
|
51
51
|
mpTransferId: string;
|
|
52
52
|
userId: string;
|
|
@@ -54,7 +54,7 @@ export declare function insertDeposit(pool: pg.Pool, o: {
|
|
|
54
54
|
amount: number;
|
|
55
55
|
currency: string;
|
|
56
56
|
}): Promise<null | undefined>;
|
|
57
|
-
export declare function processWithdrawal(
|
|
57
|
+
export declare function processWithdrawal(pgClient: PgClientInTransaction, { casinoId, mpTransferId, userId, experienceId, amount, currency, status, }: {
|
|
58
58
|
casinoId: string;
|
|
59
59
|
mpTransferId: string;
|
|
60
60
|
userId: string;
|
|
@@ -63,14 +63,14 @@ export declare function processWithdrawal(pool: pg.Pool, { casinoId, mpTransferI
|
|
|
63
63
|
currency: string;
|
|
64
64
|
status: Extract<TransferStatusKind, "PENDING" | "COMPLETED" | "CANCELED">;
|
|
65
65
|
}): Promise<void>;
|
|
66
|
-
export declare function getUnconfirmedWithdrawals(
|
|
66
|
+
export declare function getUnconfirmedWithdrawals(pgClient: QueryExecutor, { casinoId, limit, }: {
|
|
67
67
|
casinoId: string;
|
|
68
68
|
limit: number;
|
|
69
69
|
}): Promise<(DbWithdrawal & {
|
|
70
70
|
mp_experience_id: string;
|
|
71
71
|
mp_user_id: string;
|
|
72
72
|
})[]>;
|
|
73
|
-
export declare function getPendingWithdrawals(
|
|
73
|
+
export declare function getPendingWithdrawals(pgClient: QueryExecutor, { casinoId, limit, }: {
|
|
74
74
|
casinoId: string;
|
|
75
75
|
limit: number;
|
|
76
76
|
}): Promise<(DbWithdrawal & {
|
|
@@ -81,7 +81,7 @@ export declare function settleWithdrawal({ withdrawalId, newStatus, }: {
|
|
|
81
81
|
withdrawalId: string;
|
|
82
82
|
newStatus: Extract<DbTransferStatusKind, "COMPLETED" | "CANCELED">;
|
|
83
83
|
}): Promise<void>;
|
|
84
|
-
export declare function listCasinos(
|
|
84
|
+
export declare function listCasinos(pgClient: QueryExecutor): Promise<DbCasino[]>;
|
|
85
85
|
export declare function upsertCurrencies(pgClient: QueryExecutor, { casinoId, currencies, }: {
|
|
86
86
|
casinoId: string;
|
|
87
87
|
currencies: {
|
package/dist/src/db/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import pg from "pg";
|
|
1
|
+
import * as pg from "pg";
|
|
2
2
|
import config from "../config.js";
|
|
3
3
|
import stream from "node:stream";
|
|
4
4
|
import { exactlyOneRow, maybeOneRow } from "./util.js";
|
|
@@ -31,25 +31,25 @@ const PG_ERROR_CODE = {
|
|
|
31
31
|
serializationFailure: "40001",
|
|
32
32
|
};
|
|
33
33
|
export async function withPgPoolTransaction(pool, callback, retryCount = 0, maxRetries = 3) {
|
|
34
|
-
let
|
|
34
|
+
let pgClient = null;
|
|
35
35
|
try {
|
|
36
|
-
|
|
37
|
-
await
|
|
38
|
-
|
|
39
|
-
const result = await callback(
|
|
40
|
-
await
|
|
36
|
+
pgClient = await pool.connect();
|
|
37
|
+
await pgClient.query("begin isolation level serializable");
|
|
38
|
+
pgClient._inTransaction = true;
|
|
39
|
+
const result = await callback(pgClient);
|
|
40
|
+
await pgClient.query("commit");
|
|
41
41
|
return result;
|
|
42
42
|
}
|
|
43
43
|
catch (error) {
|
|
44
|
-
if (
|
|
44
|
+
if (pgClient) {
|
|
45
45
|
try {
|
|
46
|
-
await
|
|
46
|
+
await pgClient.query("rollback");
|
|
47
47
|
}
|
|
48
48
|
catch (rollbackError) {
|
|
49
49
|
logger.error("Original error:", error);
|
|
50
50
|
logger.error("Rollback failed:", rollbackError);
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
pgClient.release(true);
|
|
52
|
+
pgClient = null;
|
|
53
53
|
throw error;
|
|
54
54
|
}
|
|
55
55
|
if (retryCount < maxRetries &&
|
|
@@ -65,13 +65,13 @@ export async function withPgPoolTransaction(pool, callback, retryCount = 0, maxR
|
|
|
65
65
|
throw error;
|
|
66
66
|
}
|
|
67
67
|
finally {
|
|
68
|
-
if (
|
|
69
|
-
|
|
68
|
+
if (pgClient) {
|
|
69
|
+
pgClient.release();
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
export async function userFromActiveSessionKey(
|
|
74
|
-
const result = await
|
|
73
|
+
export async function userFromActiveSessionKey(pgClient, sessionKey) {
|
|
74
|
+
const result = await pgClient
|
|
75
75
|
.query(`
|
|
76
76
|
select u.id, u.uname, u.casino_id, s.experience_id, u.mp_user_id, s.id as session_id
|
|
77
77
|
from hub.active_session s
|
|
@@ -90,20 +90,20 @@ export async function userFromActiveSessionKey(pool, sessionKey) {
|
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
class DatabaseNotifier extends stream.EventEmitter {
|
|
93
|
-
|
|
93
|
+
pgClient;
|
|
94
94
|
constructor(connectionString) {
|
|
95
95
|
super();
|
|
96
|
-
this.
|
|
96
|
+
this.pgClient = new pg.Client({ connectionString });
|
|
97
97
|
}
|
|
98
98
|
async close() {
|
|
99
|
-
await this.
|
|
99
|
+
await this.pgClient.end();
|
|
100
100
|
logger.info("[DatabaseNotifier] Database connection closed");
|
|
101
101
|
}
|
|
102
102
|
async listen() {
|
|
103
103
|
logger.info("[DatabaseNotifier] listening for balance updates");
|
|
104
|
-
await this.
|
|
105
|
-
await this.
|
|
106
|
-
this.
|
|
104
|
+
await this.pgClient.connect();
|
|
105
|
+
await this.pgClient.query("LISTEN balance_update");
|
|
106
|
+
this.pgClient.on("notification", (notification) => {
|
|
107
107
|
if (!notification.payload) {
|
|
108
108
|
logger.error("[DatabaseNotifier] postgres notification missing payload");
|
|
109
109
|
return;
|
|
@@ -121,23 +121,23 @@ class DatabaseNotifier extends stream.EventEmitter {
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
export const notifier = new DatabaseNotifier(config.DATABASE_URL);
|
|
124
|
-
export async function getTransferCursor(
|
|
125
|
-
const row = await
|
|
124
|
+
export async function getTransferCursor(pgClient, { casinoId, }) {
|
|
125
|
+
const row = await pgClient
|
|
126
126
|
.query("select cursor from hub_hidden.transfer_cursor where casino_id = $1", [casinoId])
|
|
127
127
|
.then(maybeOneRow);
|
|
128
128
|
return row?.cursor;
|
|
129
129
|
}
|
|
130
|
-
export async function setTransferCursor(
|
|
130
|
+
export async function setTransferCursor(pgClient, { cursor, casinoId, }) {
|
|
131
131
|
console.log(`[setTransferCursor] SETTING CURSOR..... ${cursor}`);
|
|
132
|
-
await
|
|
132
|
+
await pgClient.query(`
|
|
133
133
|
insert into hub_hidden.transfer_cursor (casino_id, cursor)
|
|
134
134
|
values ($1, $2)
|
|
135
135
|
on conflict (casino_id) do update set cursor = $2
|
|
136
136
|
returning cursor
|
|
137
137
|
`, [casinoId, cursor]);
|
|
138
138
|
}
|
|
139
|
-
export async function upsertUser(
|
|
140
|
-
const user = await
|
|
139
|
+
export async function upsertUser(pgClient, { uname, casinoId, mpUserId, }) {
|
|
140
|
+
const user = await pgClient
|
|
141
141
|
.query(`
|
|
142
142
|
WITH ins AS (
|
|
143
143
|
INSERT INTO hub.user (casino_id, mp_user_id, uname)
|
|
@@ -154,8 +154,8 @@ export async function upsertUser(pool, { uname, casinoId, mpUserId, }) {
|
|
|
154
154
|
.then(exactlyOneRow);
|
|
155
155
|
return user;
|
|
156
156
|
}
|
|
157
|
-
export async function upsertExperience(
|
|
158
|
-
return
|
|
157
|
+
export async function upsertExperience(pgClient, { casinoId, mpExperienceId, name, }) {
|
|
158
|
+
return pgClient
|
|
159
159
|
.query(`
|
|
160
160
|
WITH ins AS (
|
|
161
161
|
INSERT INTO hub.experience (casino_id, mp_experience_id, name)
|
|
@@ -200,9 +200,9 @@ export async function insertDeposit(pool, o) {
|
|
|
200
200
|
`, [o.casinoId, o.userId, o.experienceId, o.currency, o.amount]);
|
|
201
201
|
});
|
|
202
202
|
}
|
|
203
|
-
export async function processWithdrawal(
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
export async function processWithdrawal(pgClient, { casinoId, mpTransferId, userId, experienceId, amount, currency, status, }) {
|
|
204
|
+
assert(pgClient._inTransaction, "pgClient must be in transaction");
|
|
205
|
+
await pgClient.query(`
|
|
206
206
|
INSERT INTO hub.withdrawal (
|
|
207
207
|
casino_id,
|
|
208
208
|
mp_transfer_id,
|
|
@@ -223,18 +223,17 @@ export async function processWithdrawal(pool, { casinoId, mpTransferId, userId,
|
|
|
223
223
|
ELSE withdrawal.status_at
|
|
224
224
|
END
|
|
225
225
|
`, [
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
});
|
|
226
|
+
casinoId,
|
|
227
|
+
mpTransferId,
|
|
228
|
+
userId,
|
|
229
|
+
experienceId,
|
|
230
|
+
amount,
|
|
231
|
+
currency,
|
|
232
|
+
status,
|
|
233
|
+
]);
|
|
235
234
|
}
|
|
236
|
-
export async function getUnconfirmedWithdrawals(
|
|
237
|
-
const result = await
|
|
235
|
+
export async function getUnconfirmedWithdrawals(pgClient, { casinoId, limit, }) {
|
|
236
|
+
const result = await pgClient.query(`
|
|
238
237
|
select
|
|
239
238
|
e.mp_experience_id mp_experience_id,
|
|
240
239
|
u.mp_user_id mp_user_id,
|
|
@@ -249,8 +248,8 @@ export async function getUnconfirmedWithdrawals(pool, { casinoId, limit, }) {
|
|
|
249
248
|
`, [casinoId, limit]);
|
|
250
249
|
return result.rows;
|
|
251
250
|
}
|
|
252
|
-
export async function getPendingWithdrawals(
|
|
253
|
-
const result = await
|
|
251
|
+
export async function getPendingWithdrawals(pgClient, { casinoId, limit, }) {
|
|
252
|
+
const result = await pgClient.query(`
|
|
254
253
|
select
|
|
255
254
|
e.mp_experience_id mp_experience_id,
|
|
256
255
|
u.mp_user_id mp_user_id,
|
|
@@ -316,8 +315,8 @@ export async function settleWithdrawal({ withdrawalId, newStatus, }) {
|
|
|
316
315
|
}
|
|
317
316
|
});
|
|
318
317
|
}
|
|
319
|
-
export async function listCasinos(
|
|
320
|
-
const result = await
|
|
318
|
+
export async function listCasinos(pgClient) {
|
|
319
|
+
const result = await pgClient.query("select * from hub.casino");
|
|
321
320
|
return result.rows;
|
|
322
321
|
}
|
|
323
322
|
export async function upsertCurrencies(pgClient, { casinoId, currencies, }) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as pg from "pg";
|
|
2
2
|
import { DbCasino, DbCasinoSecret } from "./types.js";
|
|
3
|
+
import { QueryExecutor } from "./index.js";
|
|
3
4
|
type NewCasino = Pick<DbCasino, "name" | "base_url" | "graphql_url"> & Pick<DbCasinoSecret, "controller_id" | "api_key">;
|
|
4
|
-
export declare function dbInsertCasino(pool: Pool
|
|
5
|
-
export declare function dbGetCasinoById(
|
|
6
|
-
export declare function dbGetCasinoSecretById(
|
|
5
|
+
export declare function dbInsertCasino(pool: InstanceType<typeof pg.Pool>, input: NewCasino): Promise<DbCasino>;
|
|
6
|
+
export declare function dbGetCasinoById(pgClient: QueryExecutor, casinoId: DbCasino["id"]): Promise<DbCasino | undefined>;
|
|
7
|
+
export declare function dbGetCasinoSecretById(pgClient: QueryExecutor, casinoId: DbCasino["id"]): Promise<DbCasinoSecret | undefined>;
|
|
7
8
|
export {};
|
package/dist/src/db/internal.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { exactlyOneRow, maybeOneRow } from "./util.js";
|
|
2
|
+
import { withPgPoolTransaction } from "./index.js";
|
|
2
3
|
export async function dbInsertCasino(pool, input) {
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
return withPgPoolTransaction(pool, async (pgClient) => {
|
|
5
|
+
const casino = await pgClient
|
|
6
|
+
.query(`
|
|
5
7
|
INSERT INTO hub.casino (name, base_url, graphql_url)
|
|
6
8
|
VALUES ($1, $2, $3)
|
|
7
9
|
RETURNING *
|
|
8
10
|
`, [input.name, input.base_url, input.graphql_url])
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
.then(exactlyOneRow);
|
|
12
|
+
await pgClient.query(`
|
|
11
13
|
INSERT INTO hub.casino_secret (id, controller_id, api_key)
|
|
12
14
|
VALUES ($1, $2, $3)
|
|
13
15
|
`, [casino.id, input.controller_id, input.api_key]);
|
|
14
|
-
|
|
16
|
+
return casino;
|
|
17
|
+
});
|
|
15
18
|
}
|
|
16
|
-
export async function dbGetCasinoById(
|
|
17
|
-
return
|
|
19
|
+
export async function dbGetCasinoById(pgClient, casinoId) {
|
|
20
|
+
return pgClient
|
|
18
21
|
.query(`
|
|
19
22
|
SELECT *
|
|
20
23
|
FROM hub.casino
|
|
@@ -22,8 +25,8 @@ export async function dbGetCasinoById(pool, casinoId) {
|
|
|
22
25
|
`, [casinoId])
|
|
23
26
|
.then(maybeOneRow);
|
|
24
27
|
}
|
|
25
|
-
export async function dbGetCasinoSecretById(
|
|
26
|
-
return
|
|
28
|
+
export async function dbGetCasinoSecretById(pgClient, casinoId) {
|
|
29
|
+
return pgClient
|
|
27
30
|
.query(`
|
|
28
31
|
SELECT *
|
|
29
32
|
FROM hub.casino_secret
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Express } from "express";
|
|
2
2
|
import { Logger } from "./logger.js";
|
|
3
|
+
export { MakeOutcomeBetPlugin } from "./plugins/hub-make-outcome-bet.js";
|
|
3
4
|
export { defaultPlugins, type PluginContext, type PluginIdentity, type UserSessionContext, } from "./server/graphile.config.js";
|
|
4
5
|
export type ServerOptions = {
|
|
5
6
|
configureApp?: (app: Express) => void;
|
package/dist/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createHubServer } from "./server/index.js";
|
|
|
5
5
|
import { initializeTransferProcessors } from "./process-transfers.js";
|
|
6
6
|
import { join } from "path";
|
|
7
7
|
import { logger, setLogger } from "./logger.js";
|
|
8
|
+
export { MakeOutcomeBetPlugin } from "./plugins/hub-make-outcome-bet.js";
|
|
8
9
|
export { defaultPlugins, } from "./server/graphile.config.js";
|
|
9
10
|
async function initialize(options) {
|
|
10
11
|
if (options.logger) {
|
|
@@ -54,6 +55,9 @@ async function initialize(options) {
|
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
export async function startAndListen(options) {
|
|
58
|
+
if (options.plugins && options.plugins.some((p) => typeof p === "function")) {
|
|
59
|
+
throw new Error("`plugins` should be an array of GraphileConfig.Plugin but one of the items is a function. Did you forget to call it?");
|
|
60
|
+
}
|
|
57
61
|
if (options.userDatabaseMigrationsPath &&
|
|
58
62
|
!options.userDatabaseMigrationsPath.startsWith("/")) {
|
|
59
63
|
throw new Error(`userDatabaseMigrationsPath must be an absolute path, got ${options.userDatabaseMigrationsPath}`);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
create type hub.outcome as (
|
|
2
|
+
weight float,
|
|
3
|
+
profit float
|
|
4
|
+
);
|
|
5
|
+
|
|
6
|
+
create table hub.outcome_bet (
|
|
7
|
+
id uuid primary key default hub_hidden.uuid_generate_v7(),
|
|
8
|
+
|
|
9
|
+
-- Operator-given kind like "WHEEL", "PLINKO",
|
|
10
|
+
-- Probably not worth using a postgres enum here since they are not flexible.
|
|
11
|
+
kind text not null,
|
|
12
|
+
|
|
13
|
+
user_id uuid not null references hub.user(id),
|
|
14
|
+
experience_id uuid not null references hub.experience(id),
|
|
15
|
+
casino_id uuid not null references hub.casino(id),
|
|
16
|
+
|
|
17
|
+
currency_key text not null,
|
|
18
|
+
wager float not null,
|
|
19
|
+
|
|
20
|
+
-- -1 = lose wager, -2 = lose 2x wager
|
|
21
|
+
-- 0.5 = 1.5x wager, 1 = 2x wager
|
|
22
|
+
-- In other words, a multiplier in a game might say "2.5x",
|
|
23
|
+
-- but the profit is multiplier-1 = 1.5 profit
|
|
24
|
+
profit float not null,
|
|
25
|
+
|
|
26
|
+
-- null when no outcomes saved
|
|
27
|
+
outcome_idx smallint null,
|
|
28
|
+
outcomes hub.outcome[] not null default '{}',
|
|
29
|
+
|
|
30
|
+
-- Operator-provided data per bet
|
|
31
|
+
metadata jsonb not null default '{}',
|
|
32
|
+
|
|
33
|
+
foreign key (currency_key, casino_id) references hub.currency(key, casino_id)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
create index outcome_bet_user_id_idx on hub.outcome_bet(user_id);
|
|
37
|
+
create index outcome_bet_experience_id_idx on hub.outcome_bet(experience_id);
|
|
38
|
+
create index outcome_bet_casino_id_idx on hub.outcome_bet(casino_id);
|
|
39
|
+
create index outcome_bet_kind_idx on hub.outcome_bet(kind);
|
|
40
|
+
|
|
41
|
+
-- GRANT
|
|
42
|
+
|
|
43
|
+
grant select on hub.outcome_bet to app_postgraphile;
|
|
44
|
+
|
|
45
|
+
-- RLS
|
|
46
|
+
|
|
47
|
+
alter table hub.outcome_bet enable row level security;
|
|
48
|
+
|
|
49
|
+
create policy select_outcome_bet on hub.outcome_bet for select using (
|
|
50
|
+
hub_hidden.is_operator() or
|
|
51
|
+
(
|
|
52
|
+
user_id = hub_hidden.current_user_id() and
|
|
53
|
+
experience_id = hub_hidden.current_experience_id() and
|
|
54
|
+
casino_id = hub_hidden.current_casino_id()
|
|
55
|
+
)
|
|
56
|
+
);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { object } from "grafast";
|
|
2
2
|
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
|
-
import { superuserPool, withPgPoolTransaction } from "../db/index.js";
|
|
3
|
+
import { superuserPool, withPgPoolTransaction, } from "../db/index.js";
|
|
4
4
|
import { constant, context, sideEffect } from "postgraphile/grafast";
|
|
5
|
+
import { assert } from "tsafe";
|
|
5
6
|
const CLAIM_AMOUNT = 1000;
|
|
6
7
|
export const HubClaimFaucetPlugin = makeExtendSchemaPlugin(() => {
|
|
7
8
|
return {
|
|
@@ -74,6 +75,7 @@ export const HubClaimFaucetPlugin = makeExtendSchemaPlugin(() => {
|
|
|
74
75
|
};
|
|
75
76
|
});
|
|
76
77
|
async function upsertPlayCurrency(pgClient, casinoId) {
|
|
78
|
+
assert(pgClient._inTransaction, "pgClient must be in transaction");
|
|
77
79
|
return pgClient.query({
|
|
78
80
|
text: `
|
|
79
81
|
insert into hub.currency (casino_id, key, display_unit_name, display_unit_scale)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
declare const InputSchema: z.ZodObject<{
|
|
3
|
+
kind: z.ZodString;
|
|
4
|
+
wager: z.ZodNumber;
|
|
5
|
+
currency: z.ZodString;
|
|
6
|
+
outcomes: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodObject<{
|
|
7
|
+
weight: z.ZodNumber;
|
|
8
|
+
profit: z.ZodNumber;
|
|
9
|
+
}, "strict", z.ZodTypeAny, {
|
|
10
|
+
weight: number;
|
|
11
|
+
profit: number;
|
|
12
|
+
}, {
|
|
13
|
+
weight: number;
|
|
14
|
+
profit: number;
|
|
15
|
+
}>, "many">, {
|
|
16
|
+
weight: number;
|
|
17
|
+
profit: number;
|
|
18
|
+
}[], {
|
|
19
|
+
weight: number;
|
|
20
|
+
profit: number;
|
|
21
|
+
}[]>, {
|
|
22
|
+
weight: number;
|
|
23
|
+
profit: number;
|
|
24
|
+
}[], {
|
|
25
|
+
weight: number;
|
|
26
|
+
profit: number;
|
|
27
|
+
}[]>;
|
|
28
|
+
}, "strict", z.ZodTypeAny, {
|
|
29
|
+
currency: string;
|
|
30
|
+
kind: string;
|
|
31
|
+
wager: number;
|
|
32
|
+
outcomes: {
|
|
33
|
+
weight: number;
|
|
34
|
+
profit: number;
|
|
35
|
+
}[];
|
|
36
|
+
}, {
|
|
37
|
+
currency: string;
|
|
38
|
+
kind: string;
|
|
39
|
+
wager: number;
|
|
40
|
+
outcomes: {
|
|
41
|
+
weight: number;
|
|
42
|
+
profit: number;
|
|
43
|
+
}[];
|
|
44
|
+
}>;
|
|
45
|
+
type Input = z.infer<typeof InputSchema>;
|
|
46
|
+
type BetConfig = {
|
|
47
|
+
houseEdge: number;
|
|
48
|
+
saveOutcomes: boolean;
|
|
49
|
+
getMetadata?: (input: Input) => Promise<Record<string, any>>;
|
|
50
|
+
};
|
|
51
|
+
export type BetConfigMap<BetKind extends string> = {
|
|
52
|
+
[betKind in BetKind]: BetConfig;
|
|
53
|
+
};
|
|
54
|
+
export declare function MakeOutcomeBetPlugin<BetKind extends string>({ betConfigs }: {
|
|
55
|
+
betConfigs: BetConfigMap<BetKind>;
|
|
56
|
+
}): GraphileConfig.Plugin;
|
|
57
|
+
export {};
|