@moneypot/hub 1.18.4 → 1.18.6

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.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Dashboard</title>
7
- <script type="module" crossorigin src="/dashboard/assets/index-DGxc3Ja9.js"></script>
7
+ <script type="module" crossorigin src="/dashboard/assets/index-BlgWJql2.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/dashboard/assets/index-32DtKox_.css">
9
9
  </head>
10
10
  <body>
@@ -1,6 +1,4 @@
1
- -- Flattened migrations from 001-015
2
1
 
3
- -- Schema Setup
4
2
  drop schema if exists public cascade;
5
3
  create schema public;
6
4
 
@@ -17,10 +15,6 @@ create extension if not exists pgcrypto;
17
15
  create extension if not exists "uuid-ossp";
18
16
 
19
17
 
20
- -- PostgreSQL role setup
21
- -- We need an app_postgraphile role to exist here so that we can grant it permissions.
22
- -- The user can either create it themselves before they run the migrations, or they
23
- -- can update the password after the fact.
24
18
  DO $$
25
19
  DECLARE
26
20
  random_password text := gen_random_uuid()::text;
@@ -30,21 +24,15 @@ BEGIN
30
24
  END IF;
31
25
  END $$;
32
26
 
33
- -- TODO: We may want an hub_secret for things that postgraphile user can't even do (e.g. things we only manipulate in security definer functions)
34
27
 
35
- -- UUID v7 generation functions
36
28
  CREATE OR REPLACE FUNCTION hub_hidden.uuid_generate_v7() RETURNS uuid LANGUAGE plpgsql PARALLEL SAFE AS $$
37
29
  DECLARE
38
- -- The current UNIX timestamp in milliseconds
39
30
  unix_time_ms CONSTANT bytea NOT NULL DEFAULT substring(int8send((extract(epoch FROM clock_timestamp()) * 1000)::bigint) from 3);
40
31
 
41
- -- The buffer used to create the UUID, starting with the UNIX timestamp and followed by random bytes
42
32
  buffer bytea NOT NULL DEFAULT unix_time_ms || gen_random_bytes(10);
43
33
  BEGIN
44
- -- Set most significant 4 bits of 7th byte to 7 (for UUID v7), keeping the last 4 bits unchanged
45
34
  buffer = set_byte(buffer, 6, (b'0111' || get_byte(buffer, 6)::bit(4))::bit(8)::int);
46
35
 
47
- -- Set most significant 2 bits of 9th byte to 2 (the UUID variant specified in RFC 4122), keeping the last 6 bits unchanged
48
36
  buffer = set_byte(buffer, 8, (b'10' || get_byte(buffer, 8)::bit(6))::bit(8)::int);
49
37
 
50
38
  RETURN encode(buffer, 'hex');
@@ -55,7 +43,6 @@ CREATE OR REPLACE FUNCTION extract_timestamp_from_uuid_v7(uuid_v7 UUID) RETURNS
55
43
  SELECT to_timestamp(('x'||replace(uuid_v7::text, '-', ''))::bit(48)::bigint / 1000) AS result;
56
44
  $$ LANGUAGE sql IMMUTABLE;
57
45
 
58
- -- Helper functions for RLS
59
46
  create or replace function hub_hidden.is_operator() returns boolean as $$
60
47
  select nullif(current_setting('operator.api_key', true), '') is not null;
61
48
  $$ language sql stable;
@@ -76,13 +63,11 @@ create or replace function hub_hidden.current_session_id() returns uuid as $$
76
63
  select nullif(current_setting('session.id', true), '')::uuid;
77
64
  $$ language sql stable;
78
65
 
79
- -- Enums
80
66
  create type hub.transfer_status_kind as enum ('PENDING', 'COMPLETED', 'CANCELED', 'UNCLAIMED', 'EXPIRED');
81
67
 
82
- -- Tables
83
68
  CREATE TABLE hub.casino(
84
69
  id uuid PRIMARY KEY DEFAULT hub_hidden.uuid_generate_v7(),
85
- base_url TEXT NOT NULL, -- todo: this should probably be an array..
70
+ base_url TEXT NOT NULL,
86
71
  name TEXT NOT NULL,
87
72
  graphql_url TEXT NOT NULL
88
73
  );
@@ -92,7 +77,7 @@ create unique index casino_graphql_url_key on hub.casino(graphql_url);
92
77
 
93
78
  create table hub.casino_secret(
94
79
  id uuid primary key references hub.casino(id),
95
- controller_id uuid not null, -- our controller id in the casino's system
80
+ controller_id uuid not null,
96
81
  api_key uuid not null
97
82
  );
98
83
 
@@ -102,7 +87,6 @@ create table hub.jwk_set (
102
87
  updated_at timestamptz not null default now()
103
88
  );
104
89
 
105
- -- For audit/debugging
106
90
  create table hub.jwk_set_snapshot (
107
91
  id uuid primary key default hub_hidden.uuid_generate_v7(),
108
92
  casino_id uuid not null references hub.casino(id),
@@ -113,12 +97,11 @@ create index jwks_snapshot_casino_id_idx on hub.jwk_set_snapshot(casino_id);
113
97
 
114
98
  create table hub.api_key (
115
99
  id uuid primary key default hub_hidden.uuid_generate_v7(),
116
- key uuid unique not null default gen_random_uuid(), -- uuid v4
100
+ key uuid unique not null default gen_random_uuid(),
117
101
  last_used_at timestamptz null,
118
102
  revoked_at timestamptz null
119
103
  );
120
104
 
121
- -- This will get populated from each casino graphql API.
122
105
  create table hub.currency(
123
106
  key text not null,
124
107
  casino_id uuid not null references hub.casino(id),
@@ -133,10 +116,9 @@ create table hub.user (
133
116
  id uuid NOT NULL PRIMARY KEY DEFAULT hub_hidden.uuid_generate_v7(),
134
117
  casino_id uuid NOT NULL references hub.casino(id),
135
118
  mp_user_id uuid NOT NULL,
136
- uname text NOT NULL -- from the casino
119
+ uname text NOT NULL
137
120
  );
138
121
 
139
- -- A user can only represent one mp_user_id (Moneypot record) per MP casino.
140
122
  create unique index user_casino_id_mp_user_id_key on hub.user(casino_id, mp_user_id);
141
123
 
142
124
  create table hub_hidden.transfer_cursor (
@@ -147,10 +129,9 @@ create table hub_hidden.transfer_cursor (
147
129
  create table hub.experience (
148
130
  id uuid NOT NULL PRIMARY KEY DEFAULT hub_hidden.uuid_generate_v7(),
149
131
  casino_id uuid NOT NULL references hub.casino(id),
150
- mp_experience_id uuid NOT NULL, -- graphql id of experience in MP casino
132
+ mp_experience_id uuid NOT NULL,
151
133
  name text NOT NULL
152
134
  );
153
- -- An experience can only represent one mp_experience_id (Moneypot record) per MP casino.
154
135
  CREATE UNIQUE INDEX experience_casino_id_mp_experience_id_key ON hub.experience(casino_id, mp_experience_id);
155
136
  CREATE INDEX experience_mp_experience_id_idx ON hub.experience(mp_experience_id);
156
137
 
@@ -170,11 +151,11 @@ CREATE UNIQUE INDEX bankroll_casino_id_currency_key_key ON hub.bankroll(casino_i
170
151
  CREATE INDEX bankroll_casino_id_idx ON hub.bankroll(casino_id);
171
152
 
172
153
  create table hub.session (
173
- id uuid primary key default hub_hidden.uuid_generate_v7(), --
154
+ id uuid primary key default hub_hidden.uuid_generate_v7(),
174
155
  casino_id uuid NOT NULL references hub.casino(id),
175
- user_id uuid not null references hub.user(id), -- graphql id of MP user
176
- experience_id uuid not null references hub.experience(id), -- graphql id of MP experience
177
- user_token uuid not null, -- uuid from MP user_token
156
+ user_id uuid not null references hub.user(id),
157
+ experience_id uuid not null references hub.experience(id),
158
+ user_token uuid not null,
178
159
  expired_at timestamptz not null DEFAULT now() + interval '1 year',
179
160
  key UUID NOT NULL DEFAULT gen_random_uuid()
180
161
  );
@@ -182,17 +163,15 @@ create table hub.session (
182
163
  CREATE INDEX session_casino_id_idx ON hub.session(casino_id);
183
164
  CREATE INDEX session_user_id_idx ON hub.session(user_id);
184
165
  CREATE INDEX session_experience_id_idx ON hub.session(experience_id);
185
- -- TODO: Shouldn't these only be unique per casino/exp?
186
166
  CREATE UNIQUE INDEX session_user_token_idx ON hub.session(user_token);
187
167
  CREATE UNIQUE INDEX session_key_idx ON hub.session(key);
188
168
 
189
- -- MP transfers turn into deposits and withdraws in hub
190
169
  create table hub.deposit (
191
- id uuid primary key default hub_hidden.uuid_generate_v7(),
170
+ id uuid primary key default hub_hidden.uuid_generate_v7(),
192
171
  casino_id uuid not null references hub.casino(id),
193
- mp_transfer_id text not null, -- graphql id for (external) MP casino transfer
194
- user_id uuid not null references hub.user(id),
195
- experience_id uuid not null references hub.experience(id),
172
+ mp_transfer_id text not null,
173
+ user_id uuid not null references hub.user(id),
174
+ experience_id uuid not null references hub.experience(id),
196
175
  amount float8 not null check (amount > 0),
197
176
  currency_key text not null,
198
177
  foreign key (currency_key, casino_id) references hub.currency(key, casino_id)
@@ -205,15 +184,12 @@ CREATE INDEX deposit_casino_id_idx ON hub.deposit(casino_id);
205
184
 
206
185
  create table hub.withdrawal_request (
207
186
  id uuid not null primary key default hub_hidden.uuid_generate_v7(),
208
- -- Save all the things we need to make the MP transferCurrencyExperienceToUser request
209
187
  casino_id uuid not null references hub.casino(id),
210
188
  experience_id uuid not null references hub.experience(id),
211
189
  user_id uuid not null references hub.user(id),
212
190
  amount float not null check (amount > 0),
213
191
  currency_key text not null,
214
192
 
215
- -- This is set once we can confirm the transfer was created in MP
216
- -- while submitting metadata={id: withdrawal_request.id}
217
193
  mp_transfer_id text null,
218
194
 
219
195
  foreign key (currency_key, casino_id) references hub.currency(key, casino_id)
@@ -223,15 +199,15 @@ CREATE INDEX withdrawal_request_user_id_idx ON hub.withdrawal_request(user_id);
223
199
  CREATE INDEX withdrawal_request_experience_id_idx ON hub.withdrawal_request(experience_id);
224
200
  CREATE INDEX withdrawal_request_casino_id_idx ON hub.withdrawal_request(casino_id);
225
201
 
226
- CREATE UNIQUE INDEX withdrawal_request_casino_id_mp_transfer_id_key ON hub.withdrawal_request(casino_id, mp_transfer_id)
202
+ CREATE UNIQUE INDEX withdrawal_request_casino_id_mp_transfer_id_key ON hub.withdrawal_request(casino_id, mp_transfer_id)
227
203
  WHERE mp_transfer_id IS NOT NULL;
228
204
 
229
205
  create table hub.withdrawal (
230
- id uuid primary key default hub_hidden.uuid_generate_v7(),
231
- casino_id uuid not null references hub.casino(id),
232
- mp_transfer_id text not null, -- Gets set once we confirm that MP casino has the transfer
233
- user_id uuid not null references hub.user(id),
234
- experience_id uuid not null references hub.experience(id),
206
+ id uuid primary key default hub_hidden.uuid_generate_v7(),
207
+ casino_id uuid not null references hub.casino(id),
208
+ mp_transfer_id text not null,
209
+ user_id uuid not null references hub.user(id),
210
+ experience_id uuid not null references hub.experience(id),
235
211
  amount float8 not null check (amount > 0),
236
212
  currency_key text not null,
237
213
  status hub.transfer_status_kind not null,
@@ -262,7 +238,6 @@ CREATE INDEX faucet_claim_experience_id_idx ON hub.faucet_claim(experience_id);
262
238
  CREATE INDEX faucet_claim_casino_id_idx ON hub.faucet_claim(casino_id);
263
239
  CREATE INDEX faucet_claim_currency_key_idx ON hub.faucet_claim(currency_key);
264
240
 
265
- -- User balances derived from transfers per experience
266
241
  create table hub.balance (
267
242
  casino_id uuid not null references hub.casino(id),
268
243
  user_id uuid not null references hub.user(id),
@@ -278,12 +253,9 @@ CREATE INDEX balance_user_id_idx ON hub.balance(user_id);
278
253
  CREATE INDEX balance_experience_id_idx ON hub.balance(experience_id);
279
254
  CREATE INDEX balance_casino_id_idx ON hub.balance(casino_id);
280
255
 
281
- -- Views
282
- create view hub.active_session as
256
+ create view hub.active_session as
283
257
  select * from hub.session where expired_at > now();
284
258
 
285
- -- Triggers
286
- -- Every time a new casino is inserted, a notification is sent to the channel 'new_casino'
287
259
  CREATE OR REPLACE FUNCTION notify_new_casino()
288
260
  RETURNS TRIGGER AS $$
289
261
  BEGIN
@@ -301,34 +273,29 @@ EXECUTE FUNCTION notify_new_casino();
301
273
 
302
274
  CREATE OR REPLACE FUNCTION hub.notify_balance_change() RETURNS TRIGGER AS $$
303
275
  BEGIN
304
- -- For INSERT operations, always notify
305
276
  IF TG_OP = 'INSERT' THEN
306
277
  PERFORM pg_notify(
307
278
  'hub:user:' || NEW.user_id || ':balance_alert',
308
279
  json_build_object('currency_key', NEW.currency_key)::text
309
280
  );
310
- -- For UPDATE operations, only notify if amount changed
311
281
  ELSIF TG_OP = 'UPDATE' AND NEW.amount IS DISTINCT FROM OLD.amount THEN
312
282
  PERFORM pg_notify(
313
283
  'hub:user:' || NEW.user_id || ':balance_alert',
314
284
  json_build_object('currency_key', NEW.currency_key)::text
315
285
  );
316
286
  END IF;
317
-
318
- -- trigger wants us to return new row
287
+
319
288
  RETURN NEW;
320
289
  END;
321
290
  $$ LANGUAGE plpgsql;
322
291
 
323
- CREATE TRIGGER balance_change_alert
292
+ CREATE TRIGGER balance_change_alert
324
293
  AFTER INSERT OR UPDATE OF amount ON hub.balance
325
- FOR EACH ROW
294
+ FOR EACH ROW
326
295
  EXECUTE FUNCTION hub.notify_balance_change();
327
296
 
328
- -- Grants
329
297
  grant usage on schema public to app_postgraphile;
330
298
  grant usage on schema hub to app_postgraphile;
331
- -- hub_hidden utils like hub_hidden.current_user_id() should be accessible to app_postgraphile
332
299
  grant usage on schema hub_hidden to app_postgraphile;
333
300
 
334
301
  grant select on table hub.currency to app_postgraphile;
@@ -351,7 +318,6 @@ grant select on table hub.withdrawal_request to app_postgraphile;
351
318
  grant update on hub.casino to app_postgraphile;
352
319
  grant update on table hub.bankroll to app_postgraphile;
353
320
 
354
- -- Row Level Security
355
321
  alter table hub.casino enable row level security;
356
322
  alter table hub.casino_secret enable row level security;
357
323
  alter table hub.user enable row level security;
@@ -368,14 +334,11 @@ alter table hub.jwk_set_snapshot enable row level security;
368
334
  alter table hub.withdrawal_request enable row level security;
369
335
  alter table hub.faucet_claim enable row level security;
370
336
 
371
- -- RLS Policies
372
337
 
373
- -- PUBLIC POLICIES
374
338
  create policy select_casino on hub.casino for select using (true);
375
339
  create policy select_currency on hub.currency for select using (true);
376
340
  create policy select_bankroll on hub.bankroll for select using (true);
377
341
 
378
- -- OPERATOR-ONLY POLICIES
379
342
  create policy select_experience on hub.experience for select using (
380
343
  hub_hidden.is_operator()
381
344
  );
@@ -404,55 +367,45 @@ create policy update_bankroll on hub.bankroll for update using (
404
367
  hub_hidden.is_operator()
405
368
  );
406
369
 
407
- -- MIXED-USE POLICIES
408
- -- We should scope every user check to the current experience
409
- -- Else you will accidentally see the user's rows for other experiences
410
370
 
411
371
  create policy select_user on hub.user for select using (
412
372
  hub_hidden.is_operator() or (
413
- -- Users can only see their own records
414
373
  id = hub_hidden.current_user_id()
415
374
  )
416
375
  );
417
376
 
418
377
  create policy select_balance on hub.balance for select using (
419
378
  hub_hidden.is_operator() OR (
420
- -- Users can only see their own records
421
379
  user_id = hub_hidden.current_user_id()
422
380
  )
423
381
  );
424
382
 
425
383
  create policy select_deposit on hub.deposit for select using (
426
384
  hub_hidden.is_operator() OR (
427
- -- Users can only see their own records
428
385
  user_id = hub_hidden.current_user_id()
429
386
  )
430
387
  );
431
388
 
432
389
  create policy select_withdrawal on hub.withdrawal for select using (
433
390
  hub_hidden.is_operator() OR (
434
- -- Users can only see their own records
435
391
  user_id = hub_hidden.current_user_id()
436
392
  )
437
393
  );
438
394
 
439
395
  create policy select_session on hub.session for select using (
440
396
  hub_hidden.is_operator() OR (
441
- -- Users can only see their own records
442
397
  user_id = hub_hidden.current_user_id()
443
398
  )
444
399
  );
445
400
 
446
401
  create policy select_withdrawal_request on hub.withdrawal_request for select using (
447
402
  hub_hidden.is_operator() OR (
448
- -- Users can only see their own records
449
403
  user_id = hub_hidden.current_user_id()
450
404
  )
451
405
  );
452
406
 
453
407
  create policy select_faucet_claim on hub.faucet_claim for select using (
454
408
  hub_hidden.is_operator() OR (
455
- -- Users can only see their own records
456
409
  user_id = hub_hidden.current_user_id()
457
410
  )
458
411
  );
@@ -1,11 +1,8 @@
1
- -- Add balance.id UUID PK column
2
- -- Migrate the existing surrogate PK to a unique index.
3
1
 
4
2
  ALTER TABLE hub.balance ADD COLUMN id uuid default hub_hidden.uuid_generate_v7();
5
3
  UPDATE hub.balance SET id = hub_hidden.uuid_generate_v7();
6
4
  ALTER TABLE hub.balance ALTER COLUMN id SET NOT NULL;
7
5
 
8
- -- Migrate old PK to unique index
9
6
  ALTER TABLE hub.balance DROP CONSTRAINT balance_pkey;
10
7
  ALTER TABLE hub.balance ADD CONSTRAINT balance_pkey PRIMARY KEY (id);
11
8
  CREATE UNIQUE INDEX balance_casino_id_user_id_experience_id_currency_key_key ON hub.balance(casino_id, user_id, experience_id, currency_key);
@@ -1,107 +1,85 @@
1
- -- Create a simplified take request system with a single table state machine
2
1
 
3
- -- UNDO
4
2
 
5
- -- DROP TABLE IF EXISTS hub.take_transfer;
6
- -- DROP TABLE IF EXISTS hub.take_request;
7
- -- DROP TYPE IF EXISTS hub.mp_take_request_status;
8
- -- DROP TYPE IF EXISTS hub.mp_transfer_status;
9
3
 
10
- -- Local take request status that doesn't map to MP's take_request_status kind
11
4
  CREATE TYPE hub.take_request_status AS ENUM (
12
- 'PENDING', -- Initial state
13
- 'PROCESSING', -- Funds reserved, transfer in progress
14
- 'COMPLETED', -- Transfer completed successfully
15
- 'FAILED', -- Transfer failed, needs investigation
16
- 'REJECTED' -- Request rejected (insufficient funds, etc)
5
+ 'PENDING',
6
+ 'PROCESSING',
7
+ 'COMPLETED',
8
+ 'FAILED',
9
+ 'REJECTED'
17
10
  );
18
11
 
19
- -- Maps to MP's app_public.take_request_status enum
20
12
  CREATE TYPE hub.mp_take_request_status AS ENUM (
21
- 'PENDING', -- Initial state
22
- 'TRANSFERRED', -- Experience controller successfully transferred to player
23
- 'CONTROLLER_REJECTED', -- Hub controller rejected the take request (player had zero balance)
24
- 'USER_CANCELED' -- Player canceled the take request
13
+ 'PENDING',
14
+ 'TRANSFERRED',
15
+ 'CONTROLLER_REJECTED',
16
+ 'USER_CANCELED'
25
17
  );
26
18
 
27
- -- Maps to MP's app_public.transfer_status_kind enum
28
19
  CREATE TYPE hub.mp_transfer_status AS ENUM (
29
- 'PENDING', -- Initial state
30
- 'COMPLETED', -- Balance transfer completed
31
- 'CANCELED', -- Player canceled
32
- 'UNCLAIMED', -- Controller hasn't claimed
33
- 'EXPIRED' -- Transfer expired
20
+ 'PENDING',
21
+ 'COMPLETED',
22
+ 'CANCELED',
23
+ 'UNCLAIMED',
24
+ 'EXPIRED'
34
25
  );
35
26
 
36
- -- Create the simplified take request table
37
27
  CREATE TABLE hub.take_request (
38
28
  id UUID PRIMARY KEY DEFAULT hub_hidden.uuid_generate_v7(),
39
- mp_take_request_id UUID UNIQUE NOT NULL, -- MP take request ID
29
+ mp_take_request_id UUID UNIQUE NOT NULL,
40
30
  user_id UUID NOT NULL REFERENCES hub.user(id),
41
31
  experience_id UUID NOT NULL REFERENCES hub.experience(id),
42
32
  casino_id UUID NOT NULL REFERENCES hub.casino(id),
43
33
  currency_key TEXT NOT NULL,
44
- amount FLOAT NULL, -- NULL means "take all"
34
+ amount FLOAT NULL,
45
35
  status hub.take_request_status NOT NULL DEFAULT 'PENDING',
46
- mp_status hub.mp_take_request_status NOT NULL DEFAULT 'PENDING', -- MP's take request status
47
- status_changed_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- When our status was last changed
36
+ mp_status hub.mp_take_request_status NOT NULL DEFAULT 'PENDING',
37
+ status_changed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
48
38
  reserved_amount FLOAT NOT NULL,
49
- mp_transfer_id UUID NULL, -- ID of the transfer
50
- -- mp_transfer_status is just informational
39
+ mp_transfer_id UUID NULL,
51
40
  mp_transfer_status hub.mp_transfer_status NULL,
52
- -- Whether we need to call completeTransfer
53
- transfer_needs_completion BOOLEAN NOT NULL DEFAULT TRUE,
54
- -- When we last attempted to complete the transfer
55
- transfer_completion_attempted_at TIMESTAMPTZ NULL,
41
+ transfer_needs_completion BOOLEAN NOT NULL DEFAULT TRUE,
42
+ transfer_completion_attempted_at TIMESTAMPTZ NULL,
56
43
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
57
-
44
+
58
45
  FOREIGN KEY (currency_key, casino_id) REFERENCES hub.currency(key, casino_id)
59
46
  );
60
47
 
61
- -- Create indexes for queries we'll run frequently
62
48
  CREATE INDEX take_request_casino_id_idx ON hub.take_request(casino_id);
63
49
  CREATE INDEX take_request_user_id_idx ON hub.take_request(user_id);
64
50
  CREATE INDEX take_request_experience_id_idx ON hub.take_request(experience_id);
65
51
  CREATE INDEX take_request_status_idx ON hub.take_request(status);
66
52
  CREATE INDEX take_request_updated_at_idx ON hub.take_request(updated_at);
67
- -- A mp_take_request_id is unique per casino
68
- CREATE UNIQUE INDEX take_request_casino_id_mp_take_request_id_key ON hub.take_request(casino_id, mp_take_request_id);
69
- -- A mp_transfer_id is unique per casino
53
+ CREATE UNIQUE INDEX take_request_casino_id_mp_take_request_id_key ON hub.take_request(casino_id, mp_take_request_id);
70
54
  CREATE UNIQUE INDEX take_request_casino_id_mp_transfer_id_key ON hub.take_request(casino_id, mp_transfer_id) WHERE mp_transfer_id IS NOT NULL;
71
55
 
72
56
 
73
- -- Create a function to automatically update timestamps
74
57
  CREATE OR REPLACE FUNCTION hub.update_take_request_timestamps()
75
58
  RETURNS TRIGGER AS $$
76
59
  BEGIN
77
60
  NEW.updated_at = NOW();
78
-
79
- -- Update status_changed_at if status is changing
61
+
80
62
  IF OLD.status IS DISTINCT FROM NEW.status THEN
81
63
  NEW.status_changed_at = NOW();
82
64
  END IF;
83
-
65
+
84
66
  RETURN NEW;
85
67
  END;
86
68
  $$ LANGUAGE plpgsql;
87
69
 
88
- -- Create trigger to call the function
89
70
  CREATE TRIGGER update_take_request_timestamps
90
71
  BEFORE UPDATE ON hub.take_request
91
72
  FOR EACH ROW
92
73
  EXECUTE FUNCTION hub.update_take_request_timestamps();
93
74
 
94
- -- GRANTS
95
75
 
96
76
  GRANT SELECT ON hub.take_request TO app_postgraphile;
97
77
 
98
- -- RLS
99
78
 
100
79
  ALTER TABLE hub.take_request ENABLE ROW LEVEL SECURITY;
101
80
 
102
81
  CREATE POLICY select_take_request ON hub.take_request FOR SELECT USING (
103
82
  hub_hidden.is_operator() OR (
104
- -- Users can only see their own records
105
83
  user_id = hub_hidden.current_user_id()
106
84
  )
107
85
  );
@@ -1,26 +1,18 @@
1
1
  drop policy if exists select_user on hub.user;
2
2
  create policy select_user on hub.user for select using (
3
- hub_hidden.is_operator() or
4
- -- Users can only see their own records
5
- -- Users are global and not scoped to experiences
3
+ hub_hidden.is_operator() or
6
4
  (
7
5
  id = hub_hidden.current_user_id() and
8
- -- casino_id match is redundant but we'll include it for consistency
9
6
  casino_id = hub_hidden.current_casino_id()
10
7
  )
11
8
  );
12
9
 
13
- -- These are all scoped to the current experience
14
- --
15
- -- Technically, matching on (user_id, experience_id) is sufficient since
16
- -- experience implies casino, but we'll match on all three to be explicit.
17
10
 
18
11
  drop policy if exists select_balance on hub.balance;
19
12
  create policy select_balance on hub.balance for select using (
20
- hub_hidden.is_operator() OR
21
- -- Users can only see their own records for current experience
13
+ hub_hidden.is_operator() OR
22
14
  (
23
- user_id = hub_hidden.current_user_id() and
15
+ user_id = hub_hidden.current_user_id() and
24
16
  experience_id = hub_hidden.current_experience_id() and
25
17
  casino_id = hub_hidden.current_casino_id()
26
18
  )
@@ -29,9 +21,8 @@ create policy select_balance on hub.balance for select using (
29
21
  drop policy if exists select_deposit on hub.deposit;
30
22
  create policy select_deposit on hub.deposit for select using (
31
23
  hub_hidden.is_operator() OR
32
- -- Users can only see their own records for current experience
33
24
  (
34
- user_id = hub_hidden.current_user_id() and
25
+ user_id = hub_hidden.current_user_id() and
35
26
  experience_id = hub_hidden.current_experience_id() and
36
27
  casino_id = hub_hidden.current_casino_id()
37
28
  )
@@ -40,9 +31,8 @@ create policy select_deposit on hub.deposit for select using (
40
31
  drop policy if exists select_withdrawal on hub.withdrawal;
41
32
  create policy select_withdrawal on hub.withdrawal for select using (
42
33
  hub_hidden.is_operator() OR
43
- -- Users can only see their own records for current experience
44
34
  (
45
- user_id = hub_hidden.current_user_id() and
35
+ user_id = hub_hidden.current_user_id() and
46
36
  experience_id = hub_hidden.current_experience_id() and
47
37
  casino_id = hub_hidden.current_casino_id()
48
38
  )
@@ -51,9 +41,8 @@ create policy select_withdrawal on hub.withdrawal for select using (
51
41
  drop policy if exists select_session on hub.session;
52
42
  create policy select_session on hub.session for select using (
53
43
  hub_hidden.is_operator() OR
54
- -- Users can only see their own records for current experience
55
44
  (
56
- user_id = hub_hidden.current_user_id() and
45
+ user_id = hub_hidden.current_user_id() and
57
46
  experience_id = hub_hidden.current_experience_id() and
58
47
  casino_id = hub_hidden.current_casino_id()
59
48
  )
@@ -62,9 +51,8 @@ create policy select_session on hub.session for select using (
62
51
  drop policy if exists select_withdrawal_request on hub.withdrawal_request;
63
52
  create policy select_withdrawal_request on hub.withdrawal_request for select using (
64
53
  hub_hidden.is_operator() OR
65
- -- Users can only see their own records for current experience
66
54
  (
67
- user_id = hub_hidden.current_user_id() and
55
+ user_id = hub_hidden.current_user_id() and
68
56
  experience_id = hub_hidden.current_experience_id() and
69
57
  casino_id = hub_hidden.current_casino_id()
70
58
  )
@@ -73,9 +61,8 @@ create policy select_withdrawal_request on hub.withdrawal_request for select usi
73
61
  drop policy if exists select_faucet_claim on hub.faucet_claim;
74
62
  create policy select_faucet_claim on hub.faucet_claim for select using (
75
63
  hub_hidden.is_operator() OR
76
- -- Users can only see their own records for current experience
77
64
  (
78
- user_id = hub_hidden.current_user_id() and
65
+ user_id = hub_hidden.current_user_id() and
79
66
  experience_id = hub_hidden.current_experience_id() and
80
67
  casino_id = hub_hidden.current_casino_id()
81
68
  )
@@ -10,58 +10,48 @@ CREATE TABLE hub.hash_chain (
10
10
  current_iteration int NOT NULL check (current_iteration between 0 and max_iteration)
11
11
  );
12
12
 
13
- -- TODO: Should probably index current_iteration
14
- -- CREATE INDEX hash_chain_current_iteration_idx ON hub.hash_chain(current_iteration);
15
13
 
16
14
  CREATE INDEX hash_chain_user_id_idx ON hub.hash_chain(user_id);
17
15
  CREATE INDEX hash_chain_experience_id_idx ON hub.hash_chain(experience_id);
18
16
  CREATE INDEX hash_chain_casino_id_idx ON hub.hash_chain(casino_id);
19
17
 
20
- -- Ensure only one active hash_chain per user per experience per casino
21
18
  CREATE UNIQUE INDEX active_hash_chain_idx
22
19
  ON hub.hash_chain (user_id, experience_id, casino_id)
23
20
  WHERE active = true;
24
21
 
25
22
  CREATE TYPE hub.hash_kind AS ENUM (
26
- 'TERMINAL', -- max iteration hash (e.g. iteration 1000)
27
- 'INTERMEDIATE', -- intermediate hash (e.g. iteration 1-999)
28
- 'PREIMAGE' -- preimage hash (always iteration 0)
23
+ 'TERMINAL',
24
+ 'INTERMEDIATE',
25
+ 'PREIMAGE'
29
26
  );
30
27
 
31
- -- this is the base table for all bets events
32
28
  CREATE TABLE hub.hash (
33
29
  id uuid PRIMARY KEY DEFAULT hub_hidden.uuid_generate_v7(),
34
30
  kind hub.hash_kind NOT NULL,
35
31
  hash_chain_id uuid NOT NULL REFERENCES hub.hash_chain(id),
36
- iteration int NOT NULL check (iteration >= 0), -- which Nth value from the hash chain it is
37
- digest bytea NOT NULL, -- the actual hash we got from hash chain server
38
- metadata jsonb NOT NULL DEFAULT '{}' -- operator can store game-specific tags
32
+ iteration int NOT NULL check (iteration >= 0),
33
+ digest bytea NOT NULL,
34
+ metadata jsonb NOT NULL DEFAULT '{}'
39
35
  );
40
36
 
41
37
  CREATE INDEX hash_hash_chain_id_idx ON hub.hash(hash_chain_id);
42
38
 
43
- -- Ensure iterations are unique per hash_chain to avoid dupe mistakes
44
39
  CREATE UNIQUE INDEX hash_hash_chain_id_iteration_idx ON hub.hash(hash_chain_id, iteration);
45
40
 
46
- -- Ensure a hash_chain only has of each end-type hash
47
41
  CREATE UNIQUE INDEX hash_chain_terminal_hash_idx ON hub.hash (hash_chain_id)
48
42
  WHERE kind = 'TERMINAL';
49
43
  CREATE UNIQUE INDEX hash_chain_preimage_hash_idx ON hub.hash (hash_chain_id)
50
44
  WHERE kind = 'PREIMAGE';
51
45
 
52
- -- GRANTS
53
46
 
54
47
  GRANT SELECT ON TABLE hub.hash_chain TO app_postgraphile;
55
48
  GRANT SELECT ON TABLE hub.hash TO app_postgraphile;
56
49
 
57
- -- RLS
58
50
  ALTER TABLE hub.hash_chain ENABLE ROW LEVEL SECURITY;
59
51
  ALTER TABLE hub.hash ENABLE ROW LEVEL SECURITY;
60
52
 
61
53
  CREATE POLICY select_hash_chain ON hub.hash_chain FOR SELECT USING (
62
- -- Operator can see all rows
63
54
  hub_hidden.is_operator() OR
64
- -- User can see their own rows
65
55
  (
66
56
  user_id = hub_hidden.current_user_id() AND
67
57
  experience_id = hub_hidden.current_experience_id() AND
@@ -69,14 +59,11 @@ CREATE POLICY select_hash_chain ON hub.hash_chain FOR SELECT USING (
69
59
  )
70
60
  );
71
61
 
72
- -- TODO: Since we have RLS we could just make hashes public for simplicity/perf
73
62
  CREATE POLICY select_hash ON hub.hash FOR SELECT USING (
74
- -- Operator can see all rows
75
63
  hub_hidden.is_operator() OR
76
- -- User can see their own rows by checking the associated hash_chain
77
64
  EXISTS (
78
- SELECT 1
79
- FROM hub.hash_chain
65
+ SELECT 1
66
+ FROM hub.hash_chain
80
67
  WHERE hub.hash_chain.id = hub.hash.hash_chain_id
81
68
  AND hub.hash_chain.user_id = hub_hidden.current_user_id()
82
69
  AND hub.hash_chain.experience_id = hub_hidden.current_experience_id()