@moneypot/hub 1.9.0-dev.5 → 1.9.0
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/__generated__/gql.d.ts +2 -2
- package/dist/src/__generated__/gql.js +1 -1
- package/dist/src/__generated__/graphql.d.ts +23 -5
- package/dist/src/__generated__/graphql.js +3 -1
- package/dist/src/db/index.js +1 -1
- package/dist/src/db/types.d.ts +1 -0
- package/dist/src/db/util.d.ts +4 -0
- package/dist/src/index.d.ts +5 -4
- package/dist/src/index.js +20 -11
- package/dist/src/logger.d.ts +2 -2
- package/dist/src/logger.js +1 -1
- package/dist/src/pg-versions/010-take-request-refunded-at.sql +1 -0
- package/dist/src/plugins/hub-make-outcome-bet.d.ts +1 -9
- package/dist/src/plugins/hub-make-outcome-bet.js +14 -46
- package/dist/src/process-transfers/index.js +1 -1
- package/dist/src/process-transfers/websocket-processor.js +2 -0
- package/dist/src/process-withdrawal-request.js +1 -1
- package/dist/src/risk-policy.d.ts +20 -0
- package/dist/src/risk-policy.js +61 -0
- package/dist/src/server/graphile.config.js +1 -1
- package/dist/src/take-request/process-take-request.d.ts +11 -1
- package/dist/src/take-request/process-take-request.js +62 -16
- package/package.json +1 -1
|
@@ -19,7 +19,7 @@ type Documents = {
|
|
|
19
19
|
"\n query MpPaginatedPendingTakeRequests($controllerId: UUID!, $after: Cursor) {\n allTakeRequests(\n condition: { controllerId: $controllerId, status: PENDING }\n after: $after\n orderBy: ID_ASC\n ) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n ...MpTakeRequestFields\n }\n }\n }\n }\n": typeof types.MpPaginatedPendingTakeRequestsDocument;
|
|
20
20
|
"\n mutation MpRejectTakeRequest($mpTakeRequestId: UUID!) {\n rejectTakeRequest(input: { id: $mpTakeRequestId }) {\n result {\n ... on RejectTakeRequestSuccess {\n __typename\n takeRequest {\n id\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n": typeof types.MpRejectTakeRequestDocument;
|
|
21
21
|
"\n mutation MpTransferTakeRequest(\n $mpTakeRequestId: UUID!\n $mpExperienceId: UUID!\n $mpUserId: UUID!\n $amount: Int!\n $currencyKey: String!\n ) {\n transferCurrencyExperienceToUser(\n input: {\n takeRequestId: $mpTakeRequestId\n experienceId: $mpExperienceId\n userId: $mpUserId\n amount: $amount\n currency: $currencyKey\n }\n ) {\n result {\n ... on TransferSuccess {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TransferMetadataIdExists {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n experienceTransfer {\n id\n status\n }\n }\n }\n }\n }\n }\n": typeof types.MpTransferTakeRequestDocument;
|
|
22
|
-
"\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n
|
|
22
|
+
"\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n __typename\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InsufficientBalance {\n message\n }\n ... on InvalidTransferStatus {\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n": typeof types.CompleteTransfer2Document;
|
|
23
23
|
};
|
|
24
24
|
declare const documents: Documents;
|
|
25
25
|
export declare function gql(source: string): unknown;
|
|
@@ -41,6 +41,6 @@ export declare function gql(source: "\n query MpGetTakeRequest($id: UUID!) {\n
|
|
|
41
41
|
export declare function gql(source: "\n query MpPaginatedPendingTakeRequests($controllerId: UUID!, $after: Cursor) {\n allTakeRequests(\n condition: { controllerId: $controllerId, status: PENDING }\n after: $after\n orderBy: ID_ASC\n ) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n ...MpTakeRequestFields\n }\n }\n }\n }\n"): (typeof documents)["\n query MpPaginatedPendingTakeRequests($controllerId: UUID!, $after: Cursor) {\n allTakeRequests(\n condition: { controllerId: $controllerId, status: PENDING }\n after: $after\n orderBy: ID_ASC\n ) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n ...MpTakeRequestFields\n }\n }\n }\n }\n"];
|
|
42
42
|
export declare function gql(source: "\n mutation MpRejectTakeRequest($mpTakeRequestId: UUID!) {\n rejectTakeRequest(input: { id: $mpTakeRequestId }) {\n result {\n ... on RejectTakeRequestSuccess {\n __typename\n takeRequest {\n id\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n"): (typeof documents)["\n mutation MpRejectTakeRequest($mpTakeRequestId: UUID!) {\n rejectTakeRequest(input: { id: $mpTakeRequestId }) {\n result {\n ... on RejectTakeRequestSuccess {\n __typename\n takeRequest {\n id\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n"];
|
|
43
43
|
export declare function gql(source: "\n mutation MpTransferTakeRequest(\n $mpTakeRequestId: UUID!\n $mpExperienceId: UUID!\n $mpUserId: UUID!\n $amount: Int!\n $currencyKey: String!\n ) {\n transferCurrencyExperienceToUser(\n input: {\n takeRequestId: $mpTakeRequestId\n experienceId: $mpExperienceId\n userId: $mpUserId\n amount: $amount\n currency: $currencyKey\n }\n ) {\n result {\n ... on TransferSuccess {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TransferMetadataIdExists {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n experienceTransfer {\n id\n status\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n mutation MpTransferTakeRequest(\n $mpTakeRequestId: UUID!\n $mpExperienceId: UUID!\n $mpUserId: UUID!\n $amount: Int!\n $currencyKey: String!\n ) {\n transferCurrencyExperienceToUser(\n input: {\n takeRequestId: $mpTakeRequestId\n experienceId: $mpExperienceId\n userId: $mpUserId\n amount: $amount\n currency: $currencyKey\n }\n ) {\n result {\n ... on TransferSuccess {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TransferMetadataIdExists {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n experienceTransfer {\n id\n status\n }\n }\n }\n }\n }\n }\n"];
|
|
44
|
-
export declare function gql(source: "\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n
|
|
44
|
+
export declare function gql(source: "\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n __typename\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InsufficientBalance {\n message\n }\n ... on InvalidTransferStatus {\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n __typename\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InsufficientBalance {\n message\n }\n ... on InvalidTransferStatus {\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n"];
|
|
45
45
|
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode<infer TType, any> ? TType : never;
|
|
46
46
|
export {};
|
|
@@ -18,7 +18,7 @@ const documents = {
|
|
|
18
18
|
"\n query MpPaginatedPendingTakeRequests($controllerId: UUID!, $after: Cursor) {\n allTakeRequests(\n condition: { controllerId: $controllerId, status: PENDING }\n after: $after\n orderBy: ID_ASC\n ) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n ...MpTakeRequestFields\n }\n }\n }\n }\n": types.MpPaginatedPendingTakeRequestsDocument,
|
|
19
19
|
"\n mutation MpRejectTakeRequest($mpTakeRequestId: UUID!) {\n rejectTakeRequest(input: { id: $mpTakeRequestId }) {\n result {\n ... on RejectTakeRequestSuccess {\n __typename\n takeRequest {\n id\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n": types.MpRejectTakeRequestDocument,
|
|
20
20
|
"\n mutation MpTransferTakeRequest(\n $mpTakeRequestId: UUID!\n $mpExperienceId: UUID!\n $mpUserId: UUID!\n $amount: Int!\n $currencyKey: String!\n ) {\n transferCurrencyExperienceToUser(\n input: {\n takeRequestId: $mpTakeRequestId\n experienceId: $mpExperienceId\n userId: $mpUserId\n amount: $amount\n currency: $currencyKey\n }\n ) {\n result {\n ... on TransferSuccess {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TransferMetadataIdExists {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n experienceTransfer {\n id\n status\n }\n }\n }\n }\n }\n }\n": types.MpTransferTakeRequestDocument,
|
|
21
|
-
"\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n
|
|
21
|
+
"\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n __typename\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InsufficientBalance {\n message\n }\n ... on InvalidTransferStatus {\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n": types.CompleteTransfer2Document,
|
|
22
22
|
};
|
|
23
23
|
export function gql(source) {
|
|
24
24
|
return documents[source] ?? {};
|
|
@@ -336,6 +336,17 @@ export type ChallengeFailed = {
|
|
|
336
336
|
__typename?: 'ChallengeFailed';
|
|
337
337
|
message: Scalars['String']['output'];
|
|
338
338
|
};
|
|
339
|
+
export type ChangeUserRoleInput = {
|
|
340
|
+
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
|
341
|
+
role: UserRole;
|
|
342
|
+
userId: Scalars['UUID']['input'];
|
|
343
|
+
};
|
|
344
|
+
export type ChangeUserRolePayload = {
|
|
345
|
+
__typename?: 'ChangeUserRolePayload';
|
|
346
|
+
clientMutationId?: Maybe<Scalars['String']['output']>;
|
|
347
|
+
query?: Maybe<Query>;
|
|
348
|
+
user: User;
|
|
349
|
+
};
|
|
339
350
|
export type ClaimFaucetInput = {
|
|
340
351
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
|
341
352
|
currencyKey: Scalars['String']['input'];
|
|
@@ -1281,6 +1292,7 @@ export type Mutation = {
|
|
|
1281
1292
|
cancelPendingPayout: CancelPendingPayoutPayload;
|
|
1282
1293
|
cancelTakeRequest: CancelTakeRequestPayload;
|
|
1283
1294
|
cancelTransfer?: Maybe<CancelTransferPayload>;
|
|
1295
|
+
changeUserRole?: Maybe<ChangeUserRolePayload>;
|
|
1284
1296
|
claimFaucet?: Maybe<ClaimFaucetPayload>;
|
|
1285
1297
|
claimTransfer?: Maybe<ClaimTransferPayload>;
|
|
1286
1298
|
completeTransfer?: Maybe<CompleteTransferPayload>;
|
|
@@ -1337,6 +1349,9 @@ export type MutationCancelTakeRequestArgs = {
|
|
|
1337
1349
|
export type MutationCancelTransferArgs = {
|
|
1338
1350
|
input: CancelTransferInput;
|
|
1339
1351
|
};
|
|
1352
|
+
export type MutationChangeUserRoleArgs = {
|
|
1353
|
+
input: ChangeUserRoleInput;
|
|
1354
|
+
};
|
|
1340
1355
|
export type MutationClaimFaucetArgs = {
|
|
1341
1356
|
input: ClaimFaucetInput;
|
|
1342
1357
|
};
|
|
@@ -1550,6 +1565,7 @@ export declare enum PayoutStatus {
|
|
|
1550
1565
|
New = "new",
|
|
1551
1566
|
Pending = "pending",
|
|
1552
1567
|
Rejected = "rejected",
|
|
1568
|
+
Scheduled = "scheduled",
|
|
1553
1569
|
Unconfirmed = "unconfirmed"
|
|
1554
1570
|
}
|
|
1555
1571
|
export type PayoutStatusChange = {
|
|
@@ -3237,7 +3253,8 @@ export declare enum UserOrderBy {
|
|
|
3237
3253
|
export declare enum UserRole {
|
|
3238
3254
|
Admin = "ADMIN",
|
|
3239
3255
|
Demo = "DEMO",
|
|
3240
|
-
Member = "MEMBER"
|
|
3256
|
+
Member = "MEMBER",
|
|
3257
|
+
Restricted = "RESTRICTED"
|
|
3241
3258
|
}
|
|
3242
3259
|
export type UserTransfer = Transfer & {
|
|
3243
3260
|
__typename?: 'UserTransfer';
|
|
@@ -3861,11 +3878,11 @@ export type CompleteTransfer2Mutation = {
|
|
|
3861
3878
|
result: {
|
|
3862
3879
|
__typename: 'CompleteTransferSuccess';
|
|
3863
3880
|
transfer: {
|
|
3864
|
-
__typename
|
|
3881
|
+
__typename?: 'ControllerTransfer';
|
|
3865
3882
|
id: string;
|
|
3866
3883
|
status: TransferStatusKind;
|
|
3867
3884
|
} | {
|
|
3868
|
-
__typename
|
|
3885
|
+
__typename?: 'ExperienceTransfer';
|
|
3869
3886
|
id: string;
|
|
3870
3887
|
status: TransferStatusKind;
|
|
3871
3888
|
takeRequest?: {
|
|
@@ -3874,12 +3891,13 @@ export type CompleteTransfer2Mutation = {
|
|
|
3874
3891
|
status: TakeRequestStatus;
|
|
3875
3892
|
} | null;
|
|
3876
3893
|
} | {
|
|
3877
|
-
__typename
|
|
3894
|
+
__typename?: 'UserTransfer';
|
|
3878
3895
|
id: string;
|
|
3879
3896
|
status: TransferStatusKind;
|
|
3880
3897
|
};
|
|
3881
3898
|
} | {
|
|
3882
|
-
__typename
|
|
3899
|
+
__typename: 'InsufficientBalance';
|
|
3900
|
+
message: string;
|
|
3883
3901
|
} | {
|
|
3884
3902
|
__typename: 'InvalidTransferStatus';
|
|
3885
3903
|
currentStatus: TransferStatusKind;
|
|
@@ -252,6 +252,7 @@ export var PayoutStatus;
|
|
|
252
252
|
PayoutStatus["New"] = "new";
|
|
253
253
|
PayoutStatus["Pending"] = "pending";
|
|
254
254
|
PayoutStatus["Rejected"] = "rejected";
|
|
255
|
+
PayoutStatus["Scheduled"] = "scheduled";
|
|
255
256
|
PayoutStatus["Unconfirmed"] = "unconfirmed";
|
|
256
257
|
})(PayoutStatus || (PayoutStatus = {}));
|
|
257
258
|
export var PayoutStatusChangeOrderBy;
|
|
@@ -471,6 +472,7 @@ export var UserRole;
|
|
|
471
472
|
UserRole["Admin"] = "ADMIN";
|
|
472
473
|
UserRole["Demo"] = "DEMO";
|
|
473
474
|
UserRole["Member"] = "MEMBER";
|
|
475
|
+
UserRole["Restricted"] = "RESTRICTED";
|
|
474
476
|
})(UserRole || (UserRole = {}));
|
|
475
477
|
export var UserTransferOrderBy;
|
|
476
478
|
(function (UserTransferOrderBy) {
|
|
@@ -522,4 +524,4 @@ export const MpGetTakeRequestDocument = { "kind": "Document", "definitions": [{
|
|
|
522
524
|
export const MpPaginatedPendingTakeRequestsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "MpPaginatedPendingTakeRequests" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "controllerId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "after" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Cursor" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "allTakeRequests" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "condition" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "controllerId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "controllerId" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "status" }, "value": { "kind": "EnumValue", "value": "PENDING" } }] } }, { "kind": "Argument", "name": { "kind": "Name", "value": "after" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "after" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderBy" }, "value": { "kind": "EnumValue", "value": "ID_ASC" } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "pageInfo" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "endCursor" } }, { "kind": "Field", "name": { "kind": "Name", "value": "hasNextPage" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "edges" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "cursor" } }, { "kind": "Field", "name": { "kind": "Name", "value": "node" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "MpTakeRequestFields" } }] } }] } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "MpTakeRequestFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TakeRequest" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "amount" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currencyKey" } }, { "kind": "Field", "name": { "kind": "Name", "value": "userId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceTransfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "amount" } }] } }] } }] };
|
|
523
525
|
export const MpRejectTakeRequestDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "MpRejectTakeRequest" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTakeRequestId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "rejectTakeRequest" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTakeRequestId" } } }] } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "RejectTakeRequestSuccess" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TakeRequestAlreadyTerminal" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }] } }] };
|
|
524
526
|
export const MpTransferTakeRequestDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "MpTransferTakeRequest" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTakeRequestId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpExperienceId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpUserId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "amount" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "currencyKey" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "transferCurrencyExperienceToUser" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "takeRequestId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTakeRequestId" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "experienceId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpExperienceId" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "userId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpUserId" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "amount" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "amount" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "currency" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "currencyKey" } } }] } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TransferSuccess" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TransferMetadataIdExists" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TakeRequestAlreadyTerminal" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceTransfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }] } }] } }] };
|
|
525
|
-
export const CompleteTransfer2Document = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CompleteTransfer2" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTransferId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "completeTransfer" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTransferId" } } }] } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "CompleteTransferSuccess" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "
|
|
527
|
+
export const CompleteTransfer2Document = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CompleteTransfer2" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTransferId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "completeTransfer" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTransferId" } } }] } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "CompleteTransferSuccess" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "ExperienceTransfer" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "InsufficientBalance" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "message" } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "InvalidTransferStatus" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "currentStatus" } }, { "kind": "Field", "name": { "kind": "Name", "value": "message" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "ExperienceTransfer" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }] } }] } }] } }] };
|
package/dist/src/db/index.js
CHANGED
|
@@ -132,7 +132,7 @@ export async function getTransferCursor(pgClient, { casinoId, }) {
|
|
|
132
132
|
return row?.cursor;
|
|
133
133
|
}
|
|
134
134
|
export async function setTransferCursor(pgClient, { cursor, casinoId, }) {
|
|
135
|
-
logger.debug(cursor, `[setTransferCursor] Setting cursor`);
|
|
135
|
+
logger.debug({ cursor }, `[setTransferCursor] Setting cursor`);
|
|
136
136
|
await pgClient.query(`
|
|
137
137
|
insert into hub_hidden.transfer_cursor (casino_id, cursor)
|
|
138
138
|
values ($1, $2)
|
package/dist/src/db/types.d.ts
CHANGED
|
@@ -112,6 +112,7 @@ export type DbTakeRequest = {
|
|
|
112
112
|
mp_transfer_status: DbTransferStatusKind | null;
|
|
113
113
|
transfer_needs_completion: boolean;
|
|
114
114
|
transfer_completion_attempted_at: Date | null;
|
|
115
|
+
refunded_at: Date | null;
|
|
115
116
|
updated_at: Date;
|
|
116
117
|
};
|
|
117
118
|
export type DbHashChain = {
|
package/dist/src/db/util.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { QueryResult, QueryResultRow } from "pg";
|
|
2
2
|
import { PgClientResult } from "postgraphile/@dataplan/pg";
|
|
3
|
+
import * as pg from "pg";
|
|
4
|
+
export interface QueryExecutor {
|
|
5
|
+
query<T extends pg.QueryResultRow = any>(queryText: string, values?: any[]): Promise<pg.QueryResult<T>>;
|
|
6
|
+
}
|
|
3
7
|
type ResultType<T> = PgClientResult<T> | QueryResult<T extends QueryResultRow ? T : never>;
|
|
4
8
|
export declare function maybeOneRow<T>(result: ResultType<T>): T | undefined;
|
|
5
9
|
export declare function exactlyOneRow<T>(result: ResultType<T>): T;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -15,7 +15,8 @@ declare global {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig,
|
|
18
|
+
export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig, } from "./plugins/hub-make-outcome-bet.js";
|
|
19
|
+
export { validateRisk, type RiskPolicy, type RiskPolicyArgs, type RiskLimits, } from "./risk-policy.js";
|
|
19
20
|
export type PluginContext = Grafast.Context;
|
|
20
21
|
export { defaultPlugins, type PluginIdentity, type UserSessionContext, } from "./server/graphile.config.js";
|
|
21
22
|
export type ServerOptions = {
|
|
@@ -25,7 +26,7 @@ export type ServerOptions = {
|
|
|
25
26
|
exportSchemaSDLPath?: string;
|
|
26
27
|
userDatabaseMigrationsPath?: string;
|
|
27
28
|
};
|
|
28
|
-
|
|
29
|
+
export declare function startAndListen(options: ServerOptions): Promise<{
|
|
29
30
|
port: number;
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
stop: () => Promise<void>;
|
|
32
|
+
}>;
|
package/dist/src/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { initializeTransferProcessors } from "./process-transfers/index.js";
|
|
|
6
6
|
import { join } from "path";
|
|
7
7
|
import { logger } from "./logger.js";
|
|
8
8
|
export { MakeOutcomeBetPlugin, } from "./plugins/hub-make-outcome-bet.js";
|
|
9
|
+
export { validateRisk, } from "./risk-policy.js";
|
|
9
10
|
export { defaultPlugins, } from "./server/graphile.config.js";
|
|
10
11
|
async function initialize(options) {
|
|
11
12
|
if (options.signal.aborted) {
|
|
@@ -22,7 +23,7 @@ async function initialize(options) {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
catch (e) {
|
|
25
|
-
logger.error("Error upgrading core schema"
|
|
26
|
+
logger.error(e, "Error upgrading core schema");
|
|
26
27
|
if (e instanceof DatabaseAheadError) {
|
|
27
28
|
logger.error(`${"⚠️".repeat(10)}\n@moneypot/hub database was reset to prepare for a production release and you must reset your database to continue. Please see <https://www.npmjs.com/package/@moneypot/hub#change-log> for more info.`);
|
|
28
29
|
process.exit(1);
|
|
@@ -45,9 +46,11 @@ async function initialize(options) {
|
|
|
45
46
|
logger.info("Initialization aborted by graceful shutdown");
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
if (process.env.NODE_ENV !== "test") {
|
|
50
|
+
initializeTransferProcessors({
|
|
51
|
+
signal: options.signal,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
51
54
|
}
|
|
52
55
|
export async function startAndListen(options) {
|
|
53
56
|
if (options.plugins && options.plugins.some((p) => typeof p === "function")) {
|
|
@@ -74,7 +77,7 @@ export async function startAndListen(options) {
|
|
|
74
77
|
extraPgSchemas: options.extraPgSchemas,
|
|
75
78
|
abortSignal: abortController.signal,
|
|
76
79
|
});
|
|
77
|
-
const gracefulShutdown = async () => {
|
|
80
|
+
const gracefulShutdown = async ({ exit = true } = {}) => {
|
|
78
81
|
if (isShuttingDown) {
|
|
79
82
|
logger.warn("Already shutting down.");
|
|
80
83
|
return;
|
|
@@ -86,12 +89,13 @@ export async function startAndListen(options) {
|
|
|
86
89
|
logger.info("Closing resources...");
|
|
87
90
|
hubServer.shutdown();
|
|
88
91
|
try {
|
|
92
|
+
const closeTasks = [db.notifier.close()];
|
|
93
|
+
if (process.env.NODE_ENV !== "test") {
|
|
94
|
+
closeTasks.push(db.postgraphilePool.end());
|
|
95
|
+
closeTasks.push(db.superuserPool.end());
|
|
96
|
+
}
|
|
89
97
|
await Promise.race([
|
|
90
|
-
Promise.all(
|
|
91
|
-
db.notifier.close(),
|
|
92
|
-
db.postgraphilePool.end(),
|
|
93
|
-
db.superuserPool.end(),
|
|
94
|
-
]),
|
|
98
|
+
Promise.all(closeTasks),
|
|
95
99
|
new Promise((_, reject) => setTimeout(() => reject(new Error("Database cleanup timeout")), 3000)),
|
|
96
100
|
]);
|
|
97
101
|
logger.info("Cleanup complete.");
|
|
@@ -99,13 +103,18 @@ export async function startAndListen(options) {
|
|
|
99
103
|
catch (err) {
|
|
100
104
|
logger.warn(err, "Cleanup error (proceeding anyway)");
|
|
101
105
|
}
|
|
102
|
-
|
|
106
|
+
if (exit) {
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
103
109
|
};
|
|
104
110
|
process.on("SIGINT", gracefulShutdown);
|
|
105
111
|
process.on("SIGTERM", gracefulShutdown);
|
|
106
112
|
return hubServer.listen().then(() => {
|
|
107
113
|
return {
|
|
108
114
|
port: config.PORT,
|
|
115
|
+
stop: async () => {
|
|
116
|
+
await gracefulShutdown({ exit: false });
|
|
117
|
+
},
|
|
109
118
|
};
|
|
110
119
|
});
|
|
111
120
|
}
|
package/dist/src/logger.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type Logger } from "pino";
|
|
1
|
+
import pino, { type Logger } from "pino";
|
|
2
2
|
export { type Logger };
|
|
3
|
-
export declare const logger: Logger;
|
|
3
|
+
export declare const logger: pino.Logger;
|
package/dist/src/logger.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
alter table hub.take_request add column refunded_at timestamptz
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { DbOutcome } from "../db/index.js";
|
|
3
3
|
import { Result } from "../util.js";
|
|
4
|
+
import { RiskPolicy } from "../risk-policy.js";
|
|
4
5
|
declare const InputSchema: z.ZodObject<{
|
|
5
6
|
kind: z.ZodString;
|
|
6
7
|
clientSeed: z.ZodString;
|
|
@@ -75,15 +76,6 @@ export type OutcomeBetConfig = {
|
|
|
75
76
|
export type OutcomeBetConfigMap<BetKind extends string> = {
|
|
76
77
|
[betKind in BetKind]: OutcomeBetConfig;
|
|
77
78
|
};
|
|
78
|
-
export type RiskLimits = {
|
|
79
|
-
maxWager?: number;
|
|
80
|
-
maxPayout?: number;
|
|
81
|
-
};
|
|
82
|
-
export type RiskPolicy = (args: {
|
|
83
|
-
currency: string;
|
|
84
|
-
wager: number;
|
|
85
|
-
bankroll: number;
|
|
86
|
-
}) => RiskLimits;
|
|
87
79
|
export declare function MakeOutcomeBetPlugin<BetKind extends string>({ betConfigs }: {
|
|
88
80
|
betConfigs: OutcomeBetConfigMap<BetKind>;
|
|
89
81
|
}): GraphileConfig.Plugin;
|
|
@@ -8,7 +8,7 @@ import { dbInsertHubHash, dbLockHubHashChain, } from "../hash-chain/db-hash-chai
|
|
|
8
8
|
import { getIntermediateHash, getPreimageHash, } from "../hash-chain/get-hash.js";
|
|
9
9
|
import { makeFinalHash, pickRandomOutcome } from "../hash-chain/util.js";
|
|
10
10
|
import { logger } from "../logger.js";
|
|
11
|
-
import {
|
|
11
|
+
import { validateRisk } from "../risk-policy.js";
|
|
12
12
|
const FLOAT_EPSILON = 1e-10;
|
|
13
13
|
function sum(ns) {
|
|
14
14
|
return ns.reduce((a, b) => a + b, 0);
|
|
@@ -65,10 +65,6 @@ const BetConfigsSchema = z.record(BetKindSchema, z.object({
|
|
|
65
65
|
.function()
|
|
66
66
|
.optional(),
|
|
67
67
|
}));
|
|
68
|
-
const RiskLimitsSchema = z.object({
|
|
69
|
-
maxWager: z.number().finite().int().positive().optional(),
|
|
70
|
-
maxPayout: z.number().finite().int().positive().optional(),
|
|
71
|
-
});
|
|
72
68
|
export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
73
69
|
BetConfigsSchema.parse(betConfigs);
|
|
74
70
|
const betKinds = Object.keys(betConfigs);
|
|
@@ -191,47 +187,19 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
191
187
|
throw new GraphQLError("You cannot afford the worst outcome");
|
|
192
188
|
}
|
|
193
189
|
const maxProfitMultiplier = Math.max(...input.outcomes.map((o) => o.profit));
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
wager: input.wager,
|
|
208
|
-
bankroll: dbHouseBankroll.amount,
|
|
209
|
-
})
|
|
210
|
-
: {});
|
|
211
|
-
if (!riskLimitsResult.success) {
|
|
212
|
-
logger.error(riskLimitsResult.error, "Invalid risk policy");
|
|
213
|
-
throw new GraphQLError("Invalid risk policy");
|
|
214
|
-
}
|
|
215
|
-
const riskLimits = riskLimitsResult.data;
|
|
216
|
-
if (riskLimits.maxWager != null &&
|
|
217
|
-
input.wager > riskLimits.maxWager) {
|
|
218
|
-
throw new GraphQLError(`Wager exceeds limit (${formatCurrency(riskLimits.maxWager, {
|
|
219
|
-
displayUnitName: dbCurrency.display_unit_name,
|
|
220
|
-
displayUnitScale: dbCurrency.display_unit_scale,
|
|
221
|
-
})}). Your wager: ${formatCurrency(input.wager, {
|
|
222
|
-
displayUnitName: dbCurrency.display_unit_name,
|
|
223
|
-
displayUnitScale: dbCurrency.display_unit_scale,
|
|
224
|
-
})}`);
|
|
225
|
-
}
|
|
226
|
-
if (riskLimits.maxPayout != null &&
|
|
227
|
-
maxPayout > riskLimits.maxPayout) {
|
|
228
|
-
throw new GraphQLError(`Payout exceeds limit (${formatCurrency(riskLimits.maxPayout, {
|
|
229
|
-
displayUnitName: dbCurrency.display_unit_name,
|
|
230
|
-
displayUnitScale: dbCurrency.display_unit_scale,
|
|
231
|
-
})}). Your payout: ${formatCurrency(maxPayout, {
|
|
232
|
-
displayUnitName: dbCurrency.display_unit_name,
|
|
233
|
-
displayUnitScale: dbCurrency.display_unit_scale,
|
|
234
|
-
})}`);
|
|
190
|
+
const maxPotentialPayout = input.wager * maxProfitMultiplier;
|
|
191
|
+
const riskResult = validateRisk({
|
|
192
|
+
currency: input.currency,
|
|
193
|
+
wager: input.wager,
|
|
194
|
+
bankroll: dbHouseBankroll.amount,
|
|
195
|
+
maxPotentialPayout,
|
|
196
|
+
riskPolicy: betConfig.riskPolicy,
|
|
197
|
+
displayUnitName: dbCurrency.display_unit_name,
|
|
198
|
+
displayUnitScale: dbCurrency.display_unit_scale,
|
|
199
|
+
outcomes: input.outcomes,
|
|
200
|
+
});
|
|
201
|
+
if (!riskResult.ok) {
|
|
202
|
+
throw new GraphQLError(riskResult.error);
|
|
235
203
|
}
|
|
236
204
|
const dbHashChain = await dbLockHubHashChain(pgClient, {
|
|
237
205
|
userId: session.user_id,
|
|
@@ -46,7 +46,7 @@ export function initializeTransferProcessors({ signal, }) {
|
|
|
46
46
|
await listenForNewCasinos({ signal });
|
|
47
47
|
}
|
|
48
48
|
catch (e) {
|
|
49
|
-
logger.error(`Error initializing transfer processors
|
|
49
|
+
logger.error(e, `Error initializing transfer processors`);
|
|
50
50
|
}
|
|
51
51
|
})();
|
|
52
52
|
}
|
|
@@ -7,6 +7,7 @@ import { TRANSFER_FIELDS } from "./graphql.js";
|
|
|
7
7
|
import { logger } from "../logger.js";
|
|
8
8
|
import { processTransfer } from "./process-transfer.js";
|
|
9
9
|
import assert from "assert";
|
|
10
|
+
import { superuserPool } from "../db/index.js";
|
|
10
11
|
import { mpGetTakeRequest, processSingleTakeRequest, } from "../take-request/process-take-request.js";
|
|
11
12
|
function httpToWs(url) {
|
|
12
13
|
if (url.protocol === "http:") {
|
|
@@ -107,6 +108,7 @@ export function startWebsocketProcessor({ casinoId, graphqlUrl, signal, controll
|
|
|
107
108
|
mpTakeRequest,
|
|
108
109
|
casinoId,
|
|
109
110
|
graphqlClient,
|
|
111
|
+
pool: superuserPool,
|
|
110
112
|
});
|
|
111
113
|
});
|
|
112
114
|
signal.addEventListener("abort", () => {
|
|
@@ -139,7 +139,7 @@ export async function processWithdrawalRequests({ casinoId, graphqlClient, }) {
|
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
141
|
catch (error) {
|
|
142
|
-
logger.error(`Failed to process withdrawal request ${request.id}
|
|
142
|
+
logger.error(error, `Failed to process withdrawal request ${request.id}`);
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DbOutcome } from "./db/types.js";
|
|
2
|
+
import { Result } from "./util.js";
|
|
3
|
+
export type RiskPolicyArgs = {
|
|
4
|
+
currency: string;
|
|
5
|
+
wager: number;
|
|
6
|
+
bankroll: number;
|
|
7
|
+
maxPotentialPayout: number;
|
|
8
|
+
outcomes: DbOutcome[];
|
|
9
|
+
};
|
|
10
|
+
export type RiskLimits = {
|
|
11
|
+
maxWager?: number;
|
|
12
|
+
maxPayout: number;
|
|
13
|
+
};
|
|
14
|
+
export type RiskPolicy = (args: RiskPolicyArgs) => RiskLimits;
|
|
15
|
+
export declare function validateRisk(options: RiskPolicyArgs & {
|
|
16
|
+
riskPolicy: RiskPolicy;
|
|
17
|
+
} & {
|
|
18
|
+
displayUnitName: string;
|
|
19
|
+
displayUnitScale: number;
|
|
20
|
+
}): Result<void, string>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { formatCurrency } from "./format-currency.js";
|
|
2
|
+
import { logger } from "./logger.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
const RiskLimitsSchema = z
|
|
5
|
+
.object({
|
|
6
|
+
maxWager: z.number().positive().optional(),
|
|
7
|
+
maxPayout: z.number().positive(),
|
|
8
|
+
})
|
|
9
|
+
.strict();
|
|
10
|
+
export function validateRisk(options) {
|
|
11
|
+
const { wager, bankroll, maxPotentialPayout, riskPolicy } = options;
|
|
12
|
+
if (maxPotentialPayout > bankroll) {
|
|
13
|
+
return {
|
|
14
|
+
ok: false,
|
|
15
|
+
error: `House cannot cover potential payout (${formatCurrency(maxPotentialPayout, {
|
|
16
|
+
displayUnitName: options.displayUnitName,
|
|
17
|
+
displayUnitScale: options.displayUnitScale,
|
|
18
|
+
})}). Bankroll: ${formatCurrency(bankroll, {
|
|
19
|
+
displayUnitName: options.displayUnitName,
|
|
20
|
+
displayUnitScale: options.displayUnitScale,
|
|
21
|
+
})}`,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (!riskPolicy) {
|
|
25
|
+
return { ok: true, value: undefined };
|
|
26
|
+
}
|
|
27
|
+
const limitsResult = RiskLimitsSchema.safeParse(riskPolicy(options));
|
|
28
|
+
if (!limitsResult.success) {
|
|
29
|
+
logger.error(limitsResult, "Invalid risk policy");
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
error: "Invalid risk policy",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const limits = limitsResult.data;
|
|
36
|
+
if (limits.maxWager !== undefined && wager > limits.maxWager) {
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
error: `Wager (${formatCurrency(wager, {
|
|
40
|
+
displayUnitName: options.displayUnitName,
|
|
41
|
+
displayUnitScale: options.displayUnitScale,
|
|
42
|
+
})}) exceeds limit (${formatCurrency(limits.maxWager, {
|
|
43
|
+
displayUnitName: options.displayUnitName,
|
|
44
|
+
displayUnitScale: options.displayUnitScale,
|
|
45
|
+
})})`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (maxPotentialPayout > limits.maxPayout) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
error: `Payout (${formatCurrency(maxPotentialPayout, {
|
|
52
|
+
displayUnitName: options.displayUnitName,
|
|
53
|
+
displayUnitScale: options.displayUnitScale,
|
|
54
|
+
})}) exceeds limit (${formatCurrency(limits.maxPayout, {
|
|
55
|
+
displayUnitName: options.displayUnitName,
|
|
56
|
+
displayUnitScale: options.displayUnitScale,
|
|
57
|
+
})})`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return { ok: true, value: undefined };
|
|
61
|
+
}
|
|
@@ -56,6 +56,7 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
|
|
|
56
56
|
if (!exportSchemaSDLPath.endsWith(".graphql")) {
|
|
57
57
|
throw new Error("exportSchemaSDLPath must end with .graphql");
|
|
58
58
|
}
|
|
59
|
+
logger.info(`Will save generated graphql schema to ${exportSchemaSDLPath}`);
|
|
59
60
|
}
|
|
60
61
|
const mutablePlugins = [...plugins];
|
|
61
62
|
for (const requiredPlugin of requiredPlugins) {
|
|
@@ -64,7 +65,6 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
|
|
|
64
65
|
mutablePlugins.unshift(requiredPlugin);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
|
-
logger.info(`Will save generated graphql schema to ${exportSchemaSDLPath}`);
|
|
68
68
|
const preset = {
|
|
69
69
|
extends: [PostGraphileAmberPreset],
|
|
70
70
|
disablePlugins: ["NodePlugin"],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GraphQLClient } from "graphql-request";
|
|
2
2
|
import { MpTakeRequestFieldsFragment } from "../__generated__/graphql.js";
|
|
3
|
+
import * as pg from "pg";
|
|
3
4
|
export declare const MP_TAKE_REQUEST_FIELDS: import("@graphql-typed-document-node/core").TypedDocumentNode<MpTakeRequestFieldsFragment, unknown>;
|
|
4
5
|
export declare function mpGetTakeRequest(graphqlClient: GraphQLClient, id: string): Promise<MpTakeRequestFieldsFragment | null>;
|
|
5
6
|
export declare function processTakeRequests({ abortSignal, controllerId, casinoId, graphqlClient, }: {
|
|
@@ -8,9 +9,18 @@ export declare function processTakeRequests({ abortSignal, controllerId, casinoI
|
|
|
8
9
|
casinoId: string;
|
|
9
10
|
graphqlClient: GraphQLClient;
|
|
10
11
|
}): Promise<void>;
|
|
11
|
-
export declare function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest, casinoId, graphqlClient, }: {
|
|
12
|
+
export declare function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest, casinoId, graphqlClient, pool, }: {
|
|
12
13
|
mpTakeRequestId: string;
|
|
13
14
|
mpTakeRequest?: MpTakeRequestFieldsFragment;
|
|
14
15
|
casinoId: string;
|
|
15
16
|
graphqlClient: GraphQLClient;
|
|
17
|
+
pool: pg.Pool;
|
|
16
18
|
}): Promise<string | null>;
|
|
19
|
+
export declare function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId, graphqlClient, casinoId, pool, }: {
|
|
20
|
+
mpTakeRequestId: string;
|
|
21
|
+
takeRequestId: string;
|
|
22
|
+
mpTransferId: string;
|
|
23
|
+
graphqlClient: GraphQLClient;
|
|
24
|
+
casinoId: string;
|
|
25
|
+
pool: pg.Pool;
|
|
26
|
+
}): Promise<void>;
|
|
@@ -124,10 +124,10 @@ const MP_COMPLETE_TRANSFER = gql(`
|
|
|
124
124
|
mutation CompleteTransfer2($mpTransferId: UUID!) {
|
|
125
125
|
completeTransfer(input: { id: $mpTransferId }) {
|
|
126
126
|
result {
|
|
127
|
+
__typename
|
|
127
128
|
... on CompleteTransferSuccess {
|
|
128
129
|
__typename
|
|
129
130
|
transfer {
|
|
130
|
-
__typename
|
|
131
131
|
id
|
|
132
132
|
status
|
|
133
133
|
... on ExperienceTransfer {
|
|
@@ -139,8 +139,10 @@ const MP_COMPLETE_TRANSFER = gql(`
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
... on InsufficientBalance {
|
|
143
|
+
message
|
|
144
|
+
}
|
|
142
145
|
... on InvalidTransferStatus {
|
|
143
|
-
__typename
|
|
144
146
|
currentStatus
|
|
145
147
|
message
|
|
146
148
|
transfer {
|
|
@@ -180,6 +182,7 @@ export async function processTakeRequests({ abortSignal, controllerId, casinoId,
|
|
|
180
182
|
mpTakeRequest: takeRequest,
|
|
181
183
|
casinoId,
|
|
182
184
|
graphqlClient,
|
|
185
|
+
pool: superuserPool,
|
|
183
186
|
});
|
|
184
187
|
}
|
|
185
188
|
await processPendingTransferCompletions({
|
|
@@ -200,8 +203,8 @@ async function fetchPendingTakeRequests(graphqlClient, controllerId) {
|
|
|
200
203
|
return useFragment(MP_TAKE_REQUEST_FIELDS, takeRequest);
|
|
201
204
|
}) || []);
|
|
202
205
|
}
|
|
203
|
-
export async function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest, casinoId, graphqlClient, }) {
|
|
204
|
-
return withPgPoolTransaction(
|
|
206
|
+
export async function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest, casinoId, graphqlClient, pool, }) {
|
|
207
|
+
return withPgPoolTransaction(pool, async (pgClient) => {
|
|
205
208
|
await PgAdvisoryLock.forMpTakeRequestProcessing(pgClient, {
|
|
206
209
|
mpTakeRequestId,
|
|
207
210
|
casinoId,
|
|
@@ -247,10 +250,7 @@ async function createAndProcessNewTakeRequest({ pgClient, mpTakeRequest, casinoI
|
|
|
247
250
|
currencyKey: mpTakeRequest.currencyKey,
|
|
248
251
|
casinoId,
|
|
249
252
|
});
|
|
250
|
-
|
|
251
|
-
await rejectMpTakeRequest(pgClient, graphqlClient, mpTakeRequest.id);
|
|
252
|
-
return null;
|
|
253
|
-
}
|
|
253
|
+
assert(dbUser && dbExperience && dbCurrency && dbBalance, "Required entities not found");
|
|
254
254
|
const amountToTransfer = Math.floor(typeof mpTakeRequest.amount === "number"
|
|
255
255
|
? Math.min(mpTakeRequest.amount, dbBalance.amount)
|
|
256
256
|
: dbBalance.amount);
|
|
@@ -476,15 +476,29 @@ async function processPendingTransferCompletions({ casinoId, graphqlClient, abor
|
|
|
476
476
|
mpTransferId: request.mp_transfer_id,
|
|
477
477
|
graphqlClient,
|
|
478
478
|
casinoId,
|
|
479
|
+
pool: superuserPool,
|
|
479
480
|
});
|
|
480
481
|
}
|
|
481
482
|
}
|
|
482
|
-
async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId, graphqlClient, casinoId, }) {
|
|
483
|
-
return withPgPoolTransaction(
|
|
483
|
+
export async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId, graphqlClient, casinoId, pool, }) {
|
|
484
|
+
return withPgPoolTransaction(pool, async (pgClient) => {
|
|
484
485
|
await PgAdvisoryLock.forMpTakeRequestProcessing(pgClient, {
|
|
485
486
|
mpTakeRequestId,
|
|
486
487
|
casinoId,
|
|
487
488
|
});
|
|
489
|
+
const dbTakeRequest = await pgClient
|
|
490
|
+
.query({
|
|
491
|
+
text: `
|
|
492
|
+
SELECT transfer_needs_completion
|
|
493
|
+
FROM hub.take_request
|
|
494
|
+
WHERE id = $1
|
|
495
|
+
`,
|
|
496
|
+
values: [takeRequestId],
|
|
497
|
+
})
|
|
498
|
+
.then(exactlyOneRow);
|
|
499
|
+
if (!dbTakeRequest.transfer_needs_completion) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
488
502
|
await pgClient.query({
|
|
489
503
|
text: `
|
|
490
504
|
UPDATE hub.take_request
|
|
@@ -553,26 +567,57 @@ async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId,
|
|
|
553
567
|
if (!mpStatus) {
|
|
554
568
|
throw new Error("No MP status returned from MP API");
|
|
555
569
|
}
|
|
570
|
+
const takeRequestData = await pgClient
|
|
571
|
+
.query({
|
|
572
|
+
text: `
|
|
573
|
+
SELECT *
|
|
574
|
+
FROM hub.take_request
|
|
575
|
+
WHERE id = $1
|
|
576
|
+
`,
|
|
577
|
+
values: [takeRequestId],
|
|
578
|
+
})
|
|
579
|
+
.then(exactlyOneRow);
|
|
580
|
+
if (takeRequestData.refunded_at) {
|
|
581
|
+
logger.warn({ mpTransferId, takeRequestId }, `[completeTransfer] Transfer was already refunded. This should never happen.`);
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
await pgClient.query({
|
|
585
|
+
text: `
|
|
586
|
+
UPDATE hub.balance
|
|
587
|
+
SET amount = amount + $1
|
|
588
|
+
WHERE user_id = $2
|
|
589
|
+
AND experience_id = $3
|
|
590
|
+
AND casino_id = $4
|
|
591
|
+
AND currency_key = $5
|
|
592
|
+
`,
|
|
593
|
+
values: [
|
|
594
|
+
takeRequestData.reserved_amount,
|
|
595
|
+
takeRequestData.user_id,
|
|
596
|
+
takeRequestData.experience_id,
|
|
597
|
+
takeRequestData.casino_id,
|
|
598
|
+
takeRequestData.currency_key,
|
|
599
|
+
],
|
|
600
|
+
});
|
|
556
601
|
await pgClient.query({
|
|
557
602
|
text: `
|
|
558
603
|
UPDATE hub.take_request
|
|
559
604
|
SET
|
|
560
605
|
transfer_needs_completion = FALSE,
|
|
561
606
|
mp_transfer_status = $2,
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
607
|
+
mp_status = $3,
|
|
608
|
+
debug = $4,
|
|
609
|
+
refunded_at = now(),
|
|
610
|
+
updated_at = now()
|
|
565
611
|
WHERE id = $1
|
|
566
612
|
`,
|
|
567
613
|
values: [
|
|
568
614
|
takeRequestId,
|
|
569
615
|
currentStatus,
|
|
570
|
-
LocalTakeRequestStatus.FAILED,
|
|
571
616
|
mpStatus,
|
|
572
|
-
`MP transfer was ${currentStatus}`,
|
|
617
|
+
`MP transfer was ${currentStatus}. Refunded ${takeRequestData.reserved_amount} to user`,
|
|
573
618
|
],
|
|
574
619
|
});
|
|
575
|
-
logger.info(`[completeTransfer] Transfer ${mpTransferId} has status ${currentStatus}
|
|
620
|
+
logger.info(`[completeTransfer] Transfer ${mpTransferId} has status ${currentStatus}. Refunded ${takeRequestData.reserved_amount} base units of ${takeRequestData.currency_key} to hub user.`);
|
|
576
621
|
}
|
|
577
622
|
else {
|
|
578
623
|
logger.info(`[completeTransfer] Transfer ${mpTransferId} has status ${currentStatus}, will retry later`);
|
|
@@ -665,6 +710,7 @@ async function processStuckRequests({ casinoId, graphqlClient, abortSignal, }) {
|
|
|
665
710
|
mpTakeRequestId: request.mp_take_request_id,
|
|
666
711
|
casinoId,
|
|
667
712
|
graphqlClient,
|
|
713
|
+
pool: superuserPool,
|
|
668
714
|
});
|
|
669
715
|
}
|
|
670
716
|
}
|