@flayerlabs/gamemode-gate 0.6.0 → 0.7.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/DEPLOY.md +7 -1
- package/README.md +6 -4
- package/dist/chain/chains.d.ts.map +1 -1
- package/dist/chain/chains.js +3 -1
- package/dist/chain/chains.js.map +1 -1
- package/dist/chain/signer.d.ts +19 -13
- package/dist/chain/signer.d.ts.map +1 -1
- package/dist/chain/signer.js +11 -10
- package/dist/chain/signer.js.map +1 -1
- package/dist/claims.d.ts +14 -30
- package/dist/claims.d.ts.map +1 -1
- package/dist/claims.js +55 -76
- package/dist/claims.js.map +1 -1
- package/dist/demo.d.ts +1 -1
- package/dist/demo.d.ts.map +1 -1
- package/dist/demo.js +3 -3
- package/dist/demo.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +39 -45
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +71 -172
- package/dist/ledger.js.map +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -4
- package/dist/registry.js.map +1 -1
- package/dist/room.d.ts +9 -0
- package/dist/room.d.ts.map +1 -1
- package/dist/room.js +14 -0
- package/dist/room.js.map +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +42 -35
- package/dist/server.js.map +1 -1
- package/dist/settlement.d.ts +0 -3
- package/dist/settlement.d.ts.map +1 -1
- package/dist/settlement.js +12 -44
- package/dist/settlement.js.map +1 -1
- package/dist/standings.d.ts.map +1 -1
- package/dist/standings.js +7 -1
- package/dist/standings.js.map +1 -1
- package/dist/store.d.ts +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +38 -20
- package/dist/store.js.map +1 -1
- package/dist/version.js +2 -2
- package/package.json +2 -2
- package/src/chain/chains.ts +3 -1
- package/src/chain/signer.ts +24 -30
- package/src/claims.ts +54 -78
- package/src/demo.ts +5 -5
- package/src/index.ts +1 -2
- package/src/ledger.ts +100 -248
- package/src/registry.ts +6 -3
- package/src/room.ts +15 -0
- package/src/server.ts +41 -35
- package/src/settlement.ts +12 -43
- package/src/standings.ts +9 -1
- package/src/store.ts +38 -20
- package/src/version.ts +2 -2
package/dist/ledger.d.ts
CHANGED
|
@@ -2,88 +2,82 @@ import type { Pool } from 'pg';
|
|
|
2
2
|
import type { PlayerId } from '@flayerlabs/gamemode-spec';
|
|
3
3
|
import type { EconomyBalance } from '@flayerlabs/gamemode-spec/live';
|
|
4
4
|
/**
|
|
5
|
-
* What a player has earned, what
|
|
5
|
+
* What a player has earned, what the chain says they have spent, and what is still available.
|
|
6
6
|
*
|
|
7
7
|
* Two ceilings bind, and they are different in kind. The first is what the game says they earned.
|
|
8
8
|
* The second is the pool's on-chain per-wallet cap, which the contract enforces whatever this file
|
|
9
9
|
* believes — so issuing past it does not overspend, it produces an authorisation that reverts at
|
|
10
|
-
* the swap and looks to the player like theft.
|
|
10
|
+
* the swap and looks to the player like theft. The smaller of the two is the CEILING, and the
|
|
11
|
+
* ceiling is what the gate signs: not the amount of one purchase, but the most this wallet may ever
|
|
12
|
+
* have spent on this pool. The calculator keeps its own `walletSpentWei` and refuses any swap that
|
|
13
|
+
* would carry the total past the ceiling it was handed.
|
|
11
14
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
+
* Nothing is held. Two authorisations with the same ceiling cannot add up, so an unused one costs
|
|
16
|
+
* nothing, a declined wallet dialog changes nothing, and `available` moves only when the chain
|
|
17
|
+
* shows a purchase (down) or the game awards points (up). The per-request lock this file used to
|
|
18
|
+
* take is gone with the reservation it protected; idempotency is the primary key on
|
|
19
|
+
* `authorisations` instead.
|
|
20
|
+
*
|
|
21
|
+
* One round is one pool. The pool-level `walletSpentWei` is therefore the round's spent figure,
|
|
22
|
+
* recorded per (round, player) in `balances.chain_spent_wei`.
|
|
15
23
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
/** A signed ceiling the gate handed out, kept so a retry can get the same bytes back. */
|
|
25
|
+
export interface Authorisation {
|
|
18
26
|
player: PlayerId;
|
|
19
27
|
requestId: string;
|
|
28
|
+
/** What the caller asked to spend, before clamping. */
|
|
20
29
|
requestedWei: bigint;
|
|
21
|
-
|
|
30
|
+
/** The signed cumulative ceiling: min(earned, wallet cap) at issue. */
|
|
31
|
+
spendCeilingWei: bigint;
|
|
32
|
+
/** The exact-in amount for this buy, clamped to what was available. Not signed. */
|
|
33
|
+
spendWei: bigint;
|
|
22
34
|
deadline: bigint;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
signer: `0x${string}` | null;
|
|
35
|
+
signature: `0x${string}`;
|
|
36
|
+
signer: `0x${string}`;
|
|
26
37
|
}
|
|
27
|
-
export type
|
|
38
|
+
export type Quote = {
|
|
28
39
|
ok: true;
|
|
29
|
-
|
|
40
|
+
ceiling: bigint;
|
|
41
|
+
available: bigint;
|
|
42
|
+
deadlineSeconds: bigint;
|
|
30
43
|
} | {
|
|
31
44
|
ok: false;
|
|
32
45
|
refuse: string;
|
|
33
46
|
};
|
|
34
|
-
export interface BalanceKey {
|
|
35
|
-
roundId: string;
|
|
36
|
-
player: PlayerId;
|
|
37
|
-
}
|
|
38
47
|
export declare class Ledger {
|
|
39
48
|
private readonly pool;
|
|
40
49
|
constructor(pool: Pool);
|
|
41
50
|
/** Convenience for tests and boot. The schema itself lives in store.ts. */
|
|
42
51
|
migrate(): Promise<void>;
|
|
43
52
|
/**
|
|
44
|
-
*
|
|
53
|
+
* What the gate would sign for this player right now, or why it would not.
|
|
45
54
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
55
|
+
* The deadline is the round's books close: nothing new is issued after `closesAt`, ceilings are
|
|
56
|
+
* monotone so a long-lived signature is never over-generous, and a cached authorisation must stay
|
|
57
|
+
* returnable for as long as a retry can arrive.
|
|
49
58
|
*/
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
|
|
59
|
+
quote(roundId: string, player: PlayerId, at?: number): Promise<Quote>;
|
|
60
|
+
/** The authorisation already issued for this request, if any. */
|
|
61
|
+
findAuthorisation(roundId: string, player: PlayerId, requestId: string): Promise<Authorisation | null>;
|
|
53
62
|
/**
|
|
54
|
-
*
|
|
63
|
+
* Store a signed authorisation and return the one every caller sees.
|
|
55
64
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
65
|
+
* Two replicas answering one retried request both insert; the primary key lets exactly one win,
|
|
66
|
+
* and both return the winner. Never hand out bytes that were not durably recorded, or a retry
|
|
67
|
+
* could receive a different signature for the same request id.
|
|
58
68
|
*/
|
|
59
|
-
|
|
69
|
+
storeAuthorisation(roundId: string, authorisation: Authorisation): Promise<Authorisation>;
|
|
60
70
|
/**
|
|
61
71
|
* Record what the chain says a wallet has spent on this pool.
|
|
62
72
|
*
|
|
63
73
|
* Never allowed to go backwards: a read from a lagging node must not undo what a later one saw.
|
|
64
74
|
*/
|
|
65
75
|
recordChainSpend(roundId: string, player: PlayerId, spent: bigint): Promise<boolean>;
|
|
66
|
-
/** Signed claims whose consumption still needs chain proof. Bounded per reconciliation pass. */
|
|
67
|
-
outstandingClaims(roundId: string, player: PlayerId): Promise<Claim[]>;
|
|
68
|
-
/** Caller supplies consumed nonces and cumulative spend from one verified chain snapshot. */
|
|
69
|
-
reconcileSpend(roundId: string, player: PlayerId, spent: bigint, consumed: bigint[], expiredBeforeSeconds?: bigint): Promise<boolean>;
|
|
70
76
|
/** Everyone with a balance in this round, for the reconciler to ask the chain about. */
|
|
71
77
|
playersIn(roundId: string): Promise<PlayerId[]>;
|
|
72
|
-
/**
|
|
73
|
-
* Give back every hold whose deadline has passed.
|
|
74
|
-
*
|
|
75
|
-
* An expired authorisation cannot be spent — the contract checks the same deadline — so a hold
|
|
76
|
-
* still sitting against it is allowance the player earned, cannot use, and would never get back.
|
|
77
|
-
* A player who opens the buy dialog and wanders off would otherwise lose it for the round.
|
|
78
|
-
*
|
|
79
|
-
* Returns how many were returned, so a caller can log something worth reading.
|
|
80
|
-
*/
|
|
81
|
-
releaseExpired(nowSeconds: number): Promise<BalanceKey[]>;
|
|
82
78
|
available(roundId: string, player: PlayerId): Promise<bigint>;
|
|
83
|
-
/** The authoritative balance snapshot, derived from the same state and ceiling as `
|
|
79
|
+
/** The authoritative balance snapshot, derived from the same state and ceiling as `quote`. */
|
|
84
80
|
economyBalance(roundId: string, player: PlayerId): Promise<EconomyBalance>;
|
|
85
81
|
private readState;
|
|
86
|
-
private findClaimWith;
|
|
87
|
-
private findClaimByNonce;
|
|
88
82
|
}
|
|
89
83
|
//# sourceMappingURL=ledger.d.ts.map
|
package/dist/ledger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGrE
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGrE;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,QAAQ,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,eAAe,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,KAAK,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,KAAK,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,KAAK,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACzE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAyBlC,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAEvC,2EAA2E;IACrE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B;;;;;;OAMG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,GAAE,MAAmB,GAAG,OAAO,CAAC,KAAK,CAAC;IAkBvF,iEAAiE;IAC3D,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAU5G;;;;;;OAMG;IACG,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAuB/F;;;;OAIG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1F,wFAAwF;IAClF,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAQ/C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAInE,8FAA8F;IACxF,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC;YAYlE,SAAS;CA6BxB"}
|
package/dist/ledger.js
CHANGED
|
@@ -1,25 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* Two limits bind and the smaller wins: what the game says was earned, and what the pool lets one
|
|
6
|
-
* wallet spend. Issuing past the second does not overspend — the chain refuses it — it mints a
|
|
7
|
-
* signature that reverts at the swap, which to a player is indistinguishable from being robbed.
|
|
8
|
-
*/
|
|
9
|
-
function availableFrom({ points, unitsPerPoint, capWei, held, chainSpentWei }) {
|
|
1
|
+
import { migrate, toBigInt } from './store.js';
|
|
2
|
+
/** The one place the ceiling rule lives: the smaller of what was earned and what the pool allows. */
|
|
3
|
+
function ceilingFrom({ points, unitsPerPoint, capWei }) {
|
|
10
4
|
const earned = points * unitsPerPoint;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// 40 is available and a further 40 gets authorised. Against a cap of 100 that is 140 of live
|
|
17
|
-
// authorisations, and the surplus does not overspend, it reverts at the swap, which to a player
|
|
18
|
-
// is indistinguishable from being robbed.
|
|
19
|
-
//
|
|
20
|
-
// Settlement removes proven-consumed authorisations in the same transaction as recording spend.
|
|
21
|
-
// Unverified authorisations remain held; never guess overlap from equal amounts.
|
|
22
|
-
const available = ceiling - (chainSpentWei + held);
|
|
5
|
+
return earned < capWei ? earned : capWei;
|
|
6
|
+
}
|
|
7
|
+
/** What a signed ceiling would let this wallet add right now. */
|
|
8
|
+
function availableFrom(state) {
|
|
9
|
+
const available = ceilingFrom(state) - state.chainSpentWei;
|
|
23
10
|
return available > 0n ? available : 0n;
|
|
24
11
|
}
|
|
25
12
|
export class Ledger {
|
|
@@ -32,85 +19,65 @@ export class Ledger {
|
|
|
32
19
|
await migrate(this.pool);
|
|
33
20
|
}
|
|
34
21
|
/**
|
|
35
|
-
*
|
|
22
|
+
* What the gate would sign for this player right now, or why it would not.
|
|
36
23
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
24
|
+
* The deadline is the round's books close: nothing new is issued after `closesAt`, ceilings are
|
|
25
|
+
* monotone so a long-lived signature is never over-generous, and a cached authorisation must stay
|
|
26
|
+
* returnable for as long as a retry can arrive.
|
|
40
27
|
*/
|
|
41
|
-
async
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return { ok: true, claim: existing };
|
|
61
|
-
}
|
|
62
|
-
// Existing requests deliberately win over the clock: they were issued under the earlier
|
|
63
|
-
// call's window. Only a genuinely new reservation is subject to the current instant.
|
|
64
|
-
if (at < state.opensAt)
|
|
65
|
-
return { ok: false, refuse: 'claim.not_open_yet' };
|
|
66
|
-
if (at >= state.closesAt)
|
|
67
|
-
return { ok: false, refuse: 'claim.window_closed' };
|
|
68
|
-
if (state.points <= 0n)
|
|
69
|
-
return { ok: false, refuse: 'claim.nothing_earned' };
|
|
70
|
-
const available = availableFrom(state);
|
|
71
|
-
if (available <= 0n)
|
|
72
|
-
return { ok: false, refuse: 'claim.nothing_available' };
|
|
73
|
-
const wei = upToWei < available ? upToWei : available;
|
|
74
|
-
if (wei <= 0n)
|
|
75
|
-
return { ok: false, refuse: 'claim.nothing_available' };
|
|
76
|
-
// Record the hold BEFORE anything signs against it. A signature that exists without a hold is
|
|
77
|
-
// allowance nobody is tracking; a hold without a signature is merely a refund waiting to
|
|
78
|
-
// happen. Only one of those two failures costs money.
|
|
79
|
-
const inserted = await tx.query(`insert into claims (round_id, player, request_id, requested_wei, wei, status, deadline)
|
|
80
|
-
values ($1, $2, $3, $4, $5, 'held', $6)
|
|
81
|
-
returning nonce::text, player, request_id, requested_wei::text, wei::text, deadline::text,
|
|
82
|
-
status, signature, signer`, [roundId, player, requestId, upToWei.toString(), wei.toString(), deadline.toString()]);
|
|
83
|
-
const created = inserted.rows[0];
|
|
84
|
-
if (!created)
|
|
85
|
-
throw new Error(`${roundId}: claim reservation disappeared before commit`);
|
|
86
|
-
return { ok: true, claim: claimFrom(created) };
|
|
87
|
-
});
|
|
28
|
+
async quote(roundId, player, at = Date.now()) {
|
|
29
|
+
const state = await this.readState(this.pool, roundId, player);
|
|
30
|
+
if (!state)
|
|
31
|
+
return { ok: false, refuse: 'claim.no_such_round' };
|
|
32
|
+
if (at < state.opensAt)
|
|
33
|
+
return { ok: false, refuse: 'claim.not_open_yet' };
|
|
34
|
+
if (at >= state.closesAt)
|
|
35
|
+
return { ok: false, refuse: 'claim.window_closed' };
|
|
36
|
+
if (state.points <= 0n)
|
|
37
|
+
return { ok: false, refuse: 'claim.nothing_earned' };
|
|
38
|
+
const available = availableFrom(state);
|
|
39
|
+
if (available <= 0n)
|
|
40
|
+
return { ok: false, refuse: 'claim.nothing_available' };
|
|
41
|
+
return {
|
|
42
|
+
ok: true,
|
|
43
|
+
ceiling: ceilingFrom(state),
|
|
44
|
+
available,
|
|
45
|
+
deadlineSeconds: BigInt(Math.ceil(state.booksCloseAt / 1000)),
|
|
46
|
+
};
|
|
88
47
|
}
|
|
89
|
-
/**
|
|
90
|
-
async
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (!current.signature) {
|
|
96
|
-
await tx.query(`update claims set signature = $2, signer = $3 where nonce = $1`, [
|
|
97
|
-
nonce.toString(),
|
|
98
|
-
signature,
|
|
99
|
-
signer,
|
|
100
|
-
]);
|
|
101
|
-
}
|
|
102
|
-
return this.findClaimByNonce(tx, nonce);
|
|
103
|
-
});
|
|
48
|
+
/** The authorisation already issued for this request, if any. */
|
|
49
|
+
async findAuthorisation(roundId, player, requestId) {
|
|
50
|
+
const result = await this.pool.query(`select player, request_id, requested_wei::text, spend_ceiling_wei::text, spend_wei::text,
|
|
51
|
+
deadline::text, signature, signer
|
|
52
|
+
from authorisations where round_id = $1 and player = $2 and request_id = $3`, [roundId, player, requestId]);
|
|
53
|
+
return result.rows[0] ? authorisationFrom(result.rows[0]) : null;
|
|
104
54
|
}
|
|
105
55
|
/**
|
|
106
|
-
*
|
|
56
|
+
* Store a signed authorisation and return the one every caller sees.
|
|
107
57
|
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
58
|
+
* Two replicas answering one retried request both insert; the primary key lets exactly one win,
|
|
59
|
+
* and both return the winner. Never hand out bytes that were not durably recorded, or a retry
|
|
60
|
+
* could receive a different signature for the same request id.
|
|
110
61
|
*/
|
|
111
|
-
async
|
|
112
|
-
await this.pool.query(`
|
|
113
|
-
|
|
62
|
+
async storeAuthorisation(roundId, authorisation) {
|
|
63
|
+
await this.pool.query(`insert into authorisations
|
|
64
|
+
(round_id, player, request_id, requested_wei, spend_ceiling_wei, spend_wei, deadline, signature, signer)
|
|
65
|
+
values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
66
|
+
on conflict (round_id, player, request_id) do nothing`, [
|
|
67
|
+
roundId,
|
|
68
|
+
authorisation.player,
|
|
69
|
+
authorisation.requestId,
|
|
70
|
+
authorisation.requestedWei.toString(),
|
|
71
|
+
authorisation.spendCeilingWei.toString(),
|
|
72
|
+
authorisation.spendWei.toString(),
|
|
73
|
+
authorisation.deadline.toString(),
|
|
74
|
+
authorisation.signature,
|
|
75
|
+
authorisation.signer,
|
|
76
|
+
]);
|
|
77
|
+
const stored = await this.findAuthorisation(roundId, authorisation.player, authorisation.requestId);
|
|
78
|
+
if (!stored)
|
|
79
|
+
throw new Error(`${roundId}: authorisation disappeared before it could be read back`);
|
|
80
|
+
return stored;
|
|
114
81
|
}
|
|
115
82
|
/**
|
|
116
83
|
* Record what the chain says a wallet has spent on this pool.
|
|
@@ -122,86 +89,32 @@ export class Ledger {
|
|
|
122
89
|
where round_id = $1 and player = $2 and chain_spent_wei < $3`, [roundId, player, spent.toString()]);
|
|
123
90
|
return result.rowCount === 1;
|
|
124
91
|
}
|
|
125
|
-
/** Signed claims whose consumption still needs chain proof. Bounded per reconciliation pass. */
|
|
126
|
-
async outstandingClaims(roundId, player) {
|
|
127
|
-
const result = await this.pool.query(`select nonce::text, player, request_id, requested_wei::text, wei::text, deadline::text,
|
|
128
|
-
status, signature, signer from claims
|
|
129
|
-
where round_id = $1 and player = $2 and status = 'held' and signature is not null
|
|
130
|
-
order by nonce limit 100`, [roundId, player]);
|
|
131
|
-
return result.rows.map(claimFrom);
|
|
132
|
-
}
|
|
133
|
-
/** Caller supplies consumed nonces and cumulative spend from one verified chain snapshot. */
|
|
134
|
-
async reconcileSpend(roundId, player, spent, consumed, expiredBeforeSeconds) {
|
|
135
|
-
return inTransaction(this.pool, async (tx) => {
|
|
136
|
-
const balance = await tx.query(`select chain_spent_wei from balances where round_id = $1 and player = $2 for update`, [roundId, player]);
|
|
137
|
-
if (!balance.rows[0] || spent < toBigInt(balance.rows[0].chain_spent_wei))
|
|
138
|
-
return false;
|
|
139
|
-
const updated = await tx.query(`update balances set chain_spent_wei = $3 where round_id = $1 and player = $2 and chain_spent_wei < $3`, [roundId, player, spent.toString()]);
|
|
140
|
-
const released = await tx.query(`update claims set status = 'released' where round_id = $1 and player = $2
|
|
141
|
-
and status = 'held' and ((signature is not null and nonce = any($3::bigint[]))
|
|
142
|
-
or deadline < $4::numeric)`, [roundId, player, consumed.map(String), expiredBeforeSeconds?.toString() ?? null]);
|
|
143
|
-
return (updated.rowCount ?? 0) > 0 || (released.rowCount ?? 0) > 0;
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
92
|
/** Everyone with a balance in this round, for the reconciler to ask the chain about. */
|
|
147
93
|
async playersIn(roundId) {
|
|
148
94
|
const result = await this.pool.query(`select player from balances where round_id = $1`, [roundId]);
|
|
149
95
|
return result.rows.map((row) => row.player);
|
|
150
96
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Give back every hold whose deadline has passed.
|
|
153
|
-
*
|
|
154
|
-
* An expired authorisation cannot be spent — the contract checks the same deadline — so a hold
|
|
155
|
-
* still sitting against it is allowance the player earned, cannot use, and would never get back.
|
|
156
|
-
* A player who opens the buy dialog and wanders off would otherwise lose it for the round.
|
|
157
|
-
*
|
|
158
|
-
* Returns how many were returned, so a caller can log something worth reading.
|
|
159
|
-
*/
|
|
160
|
-
async releaseExpired(nowSeconds) {
|
|
161
|
-
const result = await this.pool.query(`update claims set status = 'released'
|
|
162
|
-
where status = 'held' and deadline < $1
|
|
163
|
-
returning round_id, player`, [nowSeconds]);
|
|
164
|
-
const unique = new Map(result.rows.map((row) => [
|
|
165
|
-
`${row.round_id}\u0000${row.player}`,
|
|
166
|
-
{ roundId: row.round_id, player: row.player },
|
|
167
|
-
]));
|
|
168
|
-
return [...unique.values()];
|
|
169
|
-
}
|
|
170
97
|
async available(roundId, player) {
|
|
171
98
|
return (await this.economyBalance(roundId, player)).available;
|
|
172
99
|
}
|
|
173
|
-
/** The authoritative balance snapshot, derived from the same state and ceiling as `
|
|
100
|
+
/** The authoritative balance snapshot, derived from the same state and ceiling as `quote`. */
|
|
174
101
|
async economyBalance(roundId, player) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return this.readState(tx, roundId, player);
|
|
179
|
-
});
|
|
180
|
-
if (!state) {
|
|
181
|
-
return { unitsPerPoint: 0n, earned: 0n, held: 0n, spent: 0n, available: 0n, holdExpiresAt: null };
|
|
182
|
-
}
|
|
102
|
+
const state = await this.readState(this.pool, roundId, player);
|
|
103
|
+
if (!state)
|
|
104
|
+
return { unitsPerPoint: 0n, earned: 0n, spent: 0n, available: 0n };
|
|
183
105
|
return {
|
|
184
106
|
unitsPerPoint: state.unitsPerPoint,
|
|
185
107
|
earned: state.points * state.unitsPerPoint,
|
|
186
|
-
held: state.held,
|
|
187
108
|
spent: state.chainSpentWei,
|
|
188
109
|
available: availableFrom(state),
|
|
189
|
-
// Seconds on the way in, because that is what the contract checks against; milliseconds on
|
|
190
|
-
// the way out, because that is what a browser counts down with.
|
|
191
|
-
holdExpiresAt: state.holdExpiresAtSeconds === null ? null : state.holdExpiresAtSeconds * 1000,
|
|
192
110
|
};
|
|
193
111
|
}
|
|
194
|
-
async readState(q, roundId, player
|
|
195
|
-
const round = await q.query(`select wei_per_point, wallet_cap_wei, opens_at, closes_at from rounds where id = $1`, [roundId]);
|
|
112
|
+
async readState(q, roundId, player) {
|
|
113
|
+
const round = await q.query(`select wei_per_point, wallet_cap_wei, opens_at, closes_at, books_close_at from rounds where id = $1`, [roundId]);
|
|
196
114
|
const row = round.rows[0];
|
|
197
115
|
if (!row)
|
|
198
116
|
return null;
|
|
199
|
-
const balance = await q.query(`select points, chain_spent_wei from balances where round_id = $1 and player = $2
|
|
200
|
-
// Sum and earliest deadline together: they come from the same rows, and asking twice would let
|
|
201
|
-
// a hold expire between the two reads and report a total that no deadline explains.
|
|
202
|
-
const held = await q.query(`select coalesce(sum(wei), 0)::text as total, min(deadline)::text as earliest from claims
|
|
203
|
-
where round_id = $1 and player = $2 and status = 'held'`, [roundId, player]);
|
|
204
|
-
const earliest = held.rows[0]?.earliest;
|
|
117
|
+
const balance = await q.query(`select points, chain_spent_wei from balances where round_id = $1 and player = $2`, [roundId, player]);
|
|
205
118
|
return {
|
|
206
119
|
points: toBigInt(balance.rows[0]?.points),
|
|
207
120
|
chainSpentWei: toBigInt(balance.rows[0]?.chain_spent_wei),
|
|
@@ -209,31 +122,17 @@ export class Ledger {
|
|
|
209
122
|
capWei: toBigInt(row.wallet_cap_wei),
|
|
210
123
|
opensAt: Number(row.opens_at),
|
|
211
124
|
closesAt: Number(row.closes_at),
|
|
212
|
-
|
|
213
|
-
holdExpiresAtSeconds: earliest == null ? null : Number(earliest),
|
|
125
|
+
booksCloseAt: Number(row.books_close_at),
|
|
214
126
|
};
|
|
215
127
|
}
|
|
216
|
-
async findClaimWith(q, roundId, player, requestId) {
|
|
217
|
-
const result = await q.query(`select nonce::text, player, request_id, requested_wei::text, wei::text, deadline::text,
|
|
218
|
-
status, signature, signer
|
|
219
|
-
from claims where round_id = $1 and player = $2 and request_id = $3`, [roundId, player, requestId]);
|
|
220
|
-
return result.rows[0] ? claimFrom(result.rows[0]) : null;
|
|
221
|
-
}
|
|
222
|
-
async findClaimByNonce(q, nonce, lock = false) {
|
|
223
|
-
const result = await q.query(`select nonce::text, player, request_id, requested_wei::text, wei::text, deadline::text,
|
|
224
|
-
status, signature, signer
|
|
225
|
-
from claims where nonce = $1${lock ? ' for update' : ''}`, [nonce.toString()]);
|
|
226
|
-
return result.rows[0] ? claimFrom(result.rows[0]) : null;
|
|
227
|
-
}
|
|
228
128
|
}
|
|
229
|
-
const
|
|
230
|
-
nonce: BigInt(row.nonce),
|
|
129
|
+
const authorisationFrom = (row) => ({
|
|
231
130
|
player: row.player,
|
|
232
131
|
requestId: row.request_id,
|
|
233
132
|
requestedWei: BigInt(row.requested_wei),
|
|
234
|
-
|
|
133
|
+
spendCeilingWei: BigInt(row.spend_ceiling_wei),
|
|
134
|
+
spendWei: BigInt(row.spend_wei),
|
|
235
135
|
deadline: BigInt(row.deadline),
|
|
236
|
-
status: row.status,
|
|
237
136
|
signature: row.signature,
|
|
238
137
|
signer: row.signer,
|
|
239
138
|
});
|
package/dist/ledger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare class RegistrationConflict extends Error {
|
|
|
37
37
|
*/
|
|
38
38
|
export declare function gateOrigin(value: unknown): string;
|
|
39
39
|
/** Validate the reviewed origins a creator-owned authoritative game server may use. */
|
|
40
|
-
export declare function gameServerOrigins(value: unknown): readonly string[];
|
|
40
|
+
export declare function gameServerOrigins(value: unknown, max?: number): readonly string[];
|
|
41
41
|
/** The profile for a registration. The websocket address is derived, never supplied separately. */
|
|
42
42
|
export declare function securityProfile(registration: Pick<Registration, 'gateOrigin' | 'gameServerOrigins'>): SecurityProfile;
|
|
43
43
|
export declare function checkRegistration(entry: Registration): Registration;
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAElD,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,8EAA8E;AAC9E,qBAAa,oBAAqB,SAAQ,KAAK;;CAK9C;AAmBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA4BjD;AAED,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAuB,GAAG,SAAS,MAAM,EAAE,CAQ/F;AAED,mGAAmG;AACnG,wBAAgB,eAAe,CAC7B,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,mBAAmB,CAAC,GACnE,eAAe,CAejB;AAyBD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,CAanE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAkBhG;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,IAAI,EACV,gBAAgB,EAAE,MAAM,EACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA4B9B;AAED,wEAAwE;AACxE,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW/G"}
|
package/dist/registry.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseGameServerOrigins, } from '@flayerlabs/gamemode-spec/embed';
|
|
1
|
+
import { MAX_REVIEWED_ORIGINS, parseGameServerOrigins, } from '@flayerlabs/gamemode-spec/embed';
|
|
2
2
|
export class InvalidRegistration extends Error {
|
|
3
3
|
constructor(message) {
|
|
4
4
|
super(message);
|
|
@@ -71,10 +71,10 @@ export function gateOrigin(value) {
|
|
|
71
71
|
return url.origin;
|
|
72
72
|
}
|
|
73
73
|
/** Validate the reviewed origins a creator-owned authoritative game server may use. */
|
|
74
|
-
export function gameServerOrigins(value) {
|
|
75
|
-
const origins = parseGameServerOrigins(value);
|
|
74
|
+
export function gameServerOrigins(value, max = MAX_REVIEWED_ORIGINS) {
|
|
75
|
+
const origins = parseGameServerOrigins(value, max);
|
|
76
76
|
if (origins === null) {
|
|
77
|
-
throw new InvalidRegistration(
|
|
77
|
+
throw new InvalidRegistration(`game server origins must be at most ${max} distinct public HTTPS origins`);
|
|
78
78
|
}
|
|
79
79
|
return origins;
|
|
80
80
|
}
|
package/dist/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,EACL,sBAAsB,GAGvB,MAAM,iCAAiC,CAAC;AAkBzC,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,8EAA8E;AAC9E,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C;QACE,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,eAAe,GAAG,mEAAmE,CAAC;AAE5F,MAAM,OAAO,GAAG,mBAAmB,CAAC;AACpC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAEnC,+FAA+F;AAC/F,MAAM,MAAM,GAAG,GAAG,CAAC;AAEnB;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,mBAAmB,CAAC,2BAA2B,CAAC,CAAC;IAC1F,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG;QAAE,MAAM,IAAI,mBAAmB,CAAC,0BAA0B,CAAC,CAAC;IAElF,iGAAiG;IACjG,gGAAgG;IAChG,gCAAgC;IAChC,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,mBAAmB,CAAC,kCAAkC,CAAC,CAAC;IAElG,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,mBAAmB,CAAC,2BAA2B,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAAE,MAAM,IAAI,mBAAmB,CAAC,uCAAuC,CAAC,CAAC;IACtG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,mBAAmB,CAAC,8DAA8D,CAAC,CAAC;IAChG,CAAC;IACD,2FAA2F;IAC3F,8FAA8F;IAC9F,oDAAoD;IACpD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC;QACjE,MAAM,IAAI,mBAAmB,CAAC,8DAA8D,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,iBAAiB,CAAC,KAAc;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/room.d.ts
CHANGED
|
@@ -109,6 +109,15 @@ export declare class Room<Config, State, Event, Action, PublicView, PlayerView>
|
|
|
109
109
|
playerView(player: PlayerId): PlayerView;
|
|
110
110
|
/** The cursor a reconnecting client resumes from. */
|
|
111
111
|
sequence(): number;
|
|
112
|
+
/**
|
|
113
|
+
* Record that the round is final: every landed buy is in `spent` and nothing will change again.
|
|
114
|
+
*
|
|
115
|
+
* The server calls this once, after its last clean settlement pass past `booksCloseAt`, before it
|
|
116
|
+
* closes the room's sockets. Idempotent — the first stamp wins, so a retried teardown after a
|
|
117
|
+
* failed socket close cannot move the moment. It is what `GET /coins/:coin/rankings` reads back
|
|
118
|
+
* as `settledAt`/`final`.
|
|
119
|
+
*/
|
|
120
|
+
markSettled(at: number): Promise<void>;
|
|
112
121
|
}
|
|
113
122
|
export {};
|
|
114
123
|
//# sourceMappingURL=room.d.ts.map
|
package/dist/room.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../src/room.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../src/room.ts"],"names":[],"mappings":"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"}
|
package/dist/room.js
CHANGED
|
@@ -263,6 +263,20 @@ export class Room {
|
|
|
263
263
|
sequence() {
|
|
264
264
|
return this.seq;
|
|
265
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Record that the round is final: every landed buy is in `spent` and nothing will change again.
|
|
268
|
+
*
|
|
269
|
+
* The server calls this once, after its last clean settlement pass past `booksCloseAt`, before it
|
|
270
|
+
* closes the room's sockets. Idempotent — the first stamp wins, so a retried teardown after a
|
|
271
|
+
* failed socket close cannot move the moment. It is what `GET /coins/:coin/rankings` reads back
|
|
272
|
+
* as `settledAt`/`final`.
|
|
273
|
+
*/
|
|
274
|
+
async markSettled(at) {
|
|
275
|
+
await this.pool.query(`update rounds set settled_at = $1 where id = $2 and settled_at is null`, [
|
|
276
|
+
at,
|
|
277
|
+
this.id,
|
|
278
|
+
]);
|
|
279
|
+
}
|
|
266
280
|
}
|
|
267
281
|
/**
|
|
268
282
|
* Game state has to survive a round trip through JSON, and one thing silently does not: `bigint`
|