@moneypot/hub 1.8.0 → 1.9.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
CHANGED
|
@@ -76,6 +76,13 @@ insert into hub.api_key default values returning key;
|
|
|
76
76
|
|
|
77
77
|
## Changelog
|
|
78
78
|
|
|
79
|
+
### 1.8.x
|
|
80
|
+
|
|
81
|
+
- Added [pino](https://getpino.io) for logging.
|
|
82
|
+
- Added `LOG_LEVEL` environment variable to set the logging level. (default: `info`)
|
|
83
|
+
- Added `LOG_PRETTY` environment variable to force enable/disable pretty logging (requires `npm install pino-pretty`).
|
|
84
|
+
- Exposed `@moneypot/hub/logger`. Example: `import { logger } from "@moneypot/hub/logger";`
|
|
85
|
+
|
|
79
86
|
### 1.7.x
|
|
80
87
|
|
|
81
88
|
Updated Hub to handle breaking changes in moneypot-server GraphQL transfer API.
|
package/dist/src/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ declare global {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig, } from "./plugins/hub-make-outcome-bet.js";
|
|
18
|
+
export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig, type RiskPolicy, type RiskLimits, } from "./plugins/hub-make-outcome-bet.js";
|
|
19
19
|
export type PluginContext = Grafast.Context;
|
|
20
20
|
export { defaultPlugins, type PluginIdentity, type UserSessionContext, } from "./server/graphile.config.js";
|
|
21
21
|
export type ServerOptions = {
|
|
@@ -66,6 +66,7 @@ type FinalizeMetadataData = {
|
|
|
66
66
|
};
|
|
67
67
|
export type OutcomeBetConfig = {
|
|
68
68
|
houseEdge: number;
|
|
69
|
+
riskPolicy: RiskPolicy;
|
|
69
70
|
saveOutcomes: boolean;
|
|
70
71
|
allowLossBeyondWager?: boolean;
|
|
71
72
|
initializeMetadataFromUntrustedUserInput?: (input: Input) => Result<Metadata, string>;
|
|
@@ -74,6 +75,15 @@ export type OutcomeBetConfig = {
|
|
|
74
75
|
export type OutcomeBetConfigMap<BetKind extends string> = {
|
|
75
76
|
[betKind in BetKind]: OutcomeBetConfig;
|
|
76
77
|
};
|
|
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;
|
|
77
87
|
export declare function MakeOutcomeBetPlugin<BetKind extends string>({ betConfigs }: {
|
|
78
88
|
betConfigs: OutcomeBetConfigMap<BetKind>;
|
|
79
89
|
}): GraphileConfig.Plugin;
|
|
@@ -55,6 +55,7 @@ const BetConfigsSchema = z.record(BetKindSchema, z.object({
|
|
|
55
55
|
.gte(0, "House edge must be >= 0")
|
|
56
56
|
.lte(1, "House edge must be <= 1"),
|
|
57
57
|
saveOutcomes: z.boolean(),
|
|
58
|
+
riskPolicy: z.function(),
|
|
58
59
|
allowLossBeyondWager: z.boolean().default(false),
|
|
59
60
|
initializeMetadataFromUntrustedUserInput: z
|
|
60
61
|
.function()
|
|
@@ -63,6 +64,10 @@ const BetConfigsSchema = z.record(BetKindSchema, z.object({
|
|
|
63
64
|
.function()
|
|
64
65
|
.optional(),
|
|
65
66
|
}));
|
|
67
|
+
const RiskLimitsSchema = z.object({
|
|
68
|
+
maxWager: z.number().finite().int().positive(),
|
|
69
|
+
maxPayout: z.number().finite().int().positive(),
|
|
70
|
+
});
|
|
66
71
|
export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
67
72
|
BetConfigsSchema.parse(betConfigs);
|
|
68
73
|
const betKinds = Object.keys(betConfigs);
|
|
@@ -185,10 +190,28 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
185
190
|
throw new GraphQLError("You cannot afford the worst outcome");
|
|
186
191
|
}
|
|
187
192
|
const maxProfitMultiplier = Math.max(...input.outcomes.map((o) => o.profit));
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
const maxPayout = input.wager * maxProfitMultiplier;
|
|
194
|
+
if (maxPayout > dbHouseBankroll.amount) {
|
|
195
|
+
throw new GraphQLError(`House cannot cover potential payout (${maxPayout}). Bankroll: ${dbHouseBankroll.amount}`);
|
|
196
|
+
}
|
|
197
|
+
const riskLimitsResult = RiskLimitsSchema.safeParse(betConfig.riskPolicy
|
|
198
|
+
? betConfig.riskPolicy({
|
|
199
|
+
currency: input.currency,
|
|
200
|
+
wager: input.wager,
|
|
201
|
+
bankroll: dbHouseBankroll.amount,
|
|
202
|
+
})
|
|
203
|
+
: {});
|
|
204
|
+
if (!riskLimitsResult.success) {
|
|
205
|
+
throw new GraphQLError(`Invalid risk policy: ${riskLimitsResult.error.issues[0].message}`);
|
|
206
|
+
}
|
|
207
|
+
const riskLimits = riskLimitsResult.data;
|
|
208
|
+
if (riskLimits.maxWager != null &&
|
|
209
|
+
input.wager > riskLimits.maxWager) {
|
|
210
|
+
throw new GraphQLError(`Wager exceeds limit (${riskLimits.maxWager}). Your wager: ${input.wager}`);
|
|
211
|
+
}
|
|
212
|
+
if (riskLimits.maxPayout != null &&
|
|
213
|
+
maxPayout > riskLimits.maxPayout) {
|
|
214
|
+
throw new GraphQLError(`Payout exceeds limit (${riskLimits.maxPayout}). Your payout: ${maxPayout}`);
|
|
192
215
|
}
|
|
193
216
|
const dbHashChain = await dbLockHubHashChain(pgClient, {
|
|
194
217
|
userId: session.user_id,
|