@flayerlabs/gamemode-gate 0.5.4 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DEPLOY.md CHANGED
@@ -46,7 +46,8 @@ gate whose signatures a swap can actually verify.
46
46
  | `ROUND_MS` | no | Advertised round length. Default 90000. |
47
47
  | `MIN_LOBBY_LEAD_MS`, `GATE_ENDS_AT_GRACE_S` | no | Defaults 60000 and 10. |
48
48
  | `POINTS_PER_DOLLAR`, `USD_PER_ETH` | no | Your game's economy. Defaults 100 and 3000; `USD_PER_ETH` may be fractional. Boot refuses an economy your `rewardBounds` cannot honour. |
49
- | `SPEND_TOKENS` | no | The non-ETH paired tokens this gate runs rounds on: a JSON array of `{ "address", "usdPerToken", "walletCap" }`, the cap in that token's base units. Symbol and decimals are read from the chain at boot, and boot refuses an economy the cap cannot honour. A launch paired with a token not listed here is refused at adoption — the gate never guesses a price. Needs the paired stack (`POSITION_MANAGER` above). |
49
+ | `SPEND_TOKENS` | no | Pin a price for a non-ETH paired token: a JSON array of `{ "address", "usdPerToken", "walletCap" }`, the cap in that token's base units. Symbol and decimals are read from the chain at boot, and boot refuses an economy the cap cannot honour. Tokens not listed are priced from the manager's `PairedTokenRegistry` at adoption (below); only a token the registry does not approve is refused. Needs the paired stack (`POSITION_MANAGER` above). |
50
+ | `PAIRED_TOKEN_CAP_HEADROOM_PERCENT` | no | Default `25`. Headroom over the smallest cap a flawless round fits under when the gate sizes the cap for a registry-priced pairing in `GET /config/spend-tokens/:address`. |
50
51
 
51
52
  ## Paired-token rounds
52
53
 
@@ -59,8 +60,13 @@ that token's units. Two things make a gate able to host them:
59
60
  Sepolia. That manager also hosts flETH and native-ETH pairings, so the same gate still runs ETH
60
61
  rounds. Boot reads the stack's wiring back (dispatcher registration, the calculator's role grant,
61
62
  the router approval) and refuses with the missing call named if any is absent.
62
- 2. List the tokens in `SPEND_TOKENS`. `/config` then announces them under `spendTokens`, which is
63
- what the launch page checks a pairing against before any coin is paid for.
63
+ 2. Nothing else. The gate reads the manager's `pairedTokenRegistry()` at boot and prices every token
64
+ the registry approves through the calculator that token was registered with, at adoption, so a
65
+ pairing approved after boot is adopted with no redeploy. `/config` names the registry as
66
+ `pairedTokenRegistry`, and `GET /config/spend-tokens/<token>` serves the entry the launch page
67
+ needs before a coin is paid for — symbol, decimals, price and the per-wallet cap to write. Pin a
68
+ price with `SPEND_TOKENS` only when you must; `/config` announces pinned tokens under
69
+ `spendTokens`.
64
70
 
65
71
  Release 0.5.0 removed `usdPerEth` from the wire along with the rest of the ETH-flavoured naming.
66
72
  Round terms now always carry `spendToken` (symbol, decimals, address) and `usdPerSpendToken`, the
@@ -92,9 +98,9 @@ flow reads it from here. If `/config` is missing, the process was built without
92
98
 
93
99
  ## Hand it to Flaunch
94
100
 
95
- The public https origin you just smoke-tested is exactly the Gate URL you enter when you submit
96
- your game at `flaunch.gg/game-mode/create` — with the gate option enabled. A game submitted without
97
- it is hosted as a passive game: its security policy allows no gate connection at all, so a launch
101
+ The public https origin you just smoke-tested is exactly the Gate URL you enter for your game in
102
+ the developer dashboard at `https://flaunch.gg/game-mode/dashboard` — declare it as a network
103
+ there. A game submitted without one is hosted as a passive game: its security policy allows no gate connection at all, so a launch
98
104
  through it can never open a room. The origin must be public https (no localhost, no IPs, no
99
105
  wildcards), because the game's browser policy only permits the origin you submitted.
100
106
 
package/README.md CHANGED
@@ -62,6 +62,9 @@ Add the chain services used by your deployment:
62
62
 
63
63
  - `Discovery` verifies each launch before the gate adopts it
64
64
  - `Settlement` updates recorded spending from the chain
65
+ - `RegistryPrices` prices any pairing the manager's PairedTokenRegistry approves, from the
66
+ calculator it was registered with; pass its `priceFor` and serve `announceSpendToken` so a new
67
+ approval needs no gate change (`startGate` does both)
65
68
 
66
69
  In 0.5.4, pass a full viem public client (including `getBlock`) to `Settlement`. It retires consumed
67
70
  claims and records spend atomically after two block confirmations and the next reconciliation pass.
@@ -137,6 +140,11 @@ const app = createGameServerGate({
137
140
  The addresses are per chain (the pair above is Base Sepolia); announce a signer you actually hold —
138
141
  launches write it into their pools as the trusted signer. Verify with `curl https://<gate>/config`.
139
142
 
143
+ The served response adds `gateVersion`, the version of `@flayerlabs/gamemode-gate` answering. The
144
+ route sets it; an announcement cannot override it. `GET /stats` carries the same field, and the
145
+ package exports `GATE_VERSION` for logs. The Flaunch dashboard reads it to confirm a gate runs a
146
+ current SDK.
147
+
140
148
  Generate a random 256-bit award token, for example with `openssl rand -hex 32`. Keep it on the gate
141
149
  and authoritative game server. Never send it to the browser or use a memorable value.
142
150
 
@@ -201,3 +209,19 @@ Read the current request and response behaviour in the
201
209
  For custom gate assembly, pass `readiness: createGateReadiness({ origin, chainId,
202
210
  positionManager, signer, pool, client })` using the gameplay dependencies. `startGate` wires this
203
211
  automatically. See [readiness setup](https://github.com/flayerlabs/gamemode-sdk/blob/main/docs/guides/run-a-gate.md#register-networks-and-prove-readiness).
212
+
213
+ ## Serve play analytics
214
+
215
+ Every gate serves `GET /stats/plays` for the Flaunch developer dashboard. It returns durable
216
+ per-game play counts that survive a room ending: `{ trackingSince, sessions, nextCursor }`, where
217
+ each session carries `id`, `coin` and `startedAt` (Unix milliseconds).
218
+
219
+ The gate records one accepted session per wallet and round on every join path — the SDK-managed
220
+ join, the external-server join and the external-server ticket. Reconnects and repeated joins keep
221
+ the first timestamp. Session IDs are stable hashes; wallet addresses are never returned. Rounds
222
+ without a coin (practice and mock rooms) are excluded.
223
+
224
+ The route returns at most 250 rows ordered by start time and ID. Pass `nextCursor` back as
225
+ `?cursor=` to continue; `null` ends the pass. A malformed cursor returns `400`. Consumers should
226
+ deduplicate by `id` and validate `coin` against their own launch pins. `trackingSince` is the time
227
+ the migration first ran on that gate: earlier plays are not counted.
@@ -0,0 +1,69 @@
1
+ import { type PublicClient } from 'viem';
2
+ import type { AnnouncedSpendToken, PriceFor } from '../server.js';
3
+ /** The subset of a viem public client this module needs, so tests can script it. */
4
+ export type RegistryReader = Pick<PublicClient, 'readContract'>;
5
+ export interface RegistryPricesOptions {
6
+ /** The manager whose registry decides which pairings exist. */
7
+ positionManager: `0x${string}`;
8
+ /** The chain's flETH wrapper, priced as ETH and never asked of the registry. */
9
+ fleth?: `0x${string}`;
10
+ /** Dollars per ETH; every registry quote is in ETH. */
11
+ usdPerEth: number;
12
+ /** How long a quote is reused, in milliseconds. */
13
+ ttlMs?: number;
14
+ /** Injectable for tests. */
15
+ now?: () => number;
16
+ }
17
+ export interface RegistryQuote {
18
+ /** Dollars per whole token, to eight significant digits. */
19
+ usdPerToken: number;
20
+ /** Whole tokens per ETH as the registry's calculator quoted them. */
21
+ tokensPerEth: number;
22
+ priceCalculator: `0x${string}`;
23
+ }
24
+ /** What `/config/spend-tokens/:address` needs to size a launch's cap. */
25
+ export interface AnnounceOptions {
26
+ maxPointsPerPlayer: number;
27
+ pointsPerDollar: number;
28
+ /** Percent added over the smallest cap a flawless round fits under. */
29
+ headroomPercent: number;
30
+ }
31
+ export declare class RegistryPrices {
32
+ private readonly client;
33
+ private readonly options;
34
+ private registry;
35
+ private readonly quotes;
36
+ private readonly ttlMs;
37
+ private readonly now;
38
+ constructor(client: RegistryReader, options: RegistryPricesOptions);
39
+ /**
40
+ * The registry the manager names, or null for a manager that predates paired tokens. Read once:
41
+ * the address is immutable on chain, and a gate serves exactly one manager.
42
+ */
43
+ registryAddress(): Promise<`0x${string}` | null>;
44
+ /** ETH by any name is the operator's `USD_PER_ETH`; it is never asked of the registry. */
45
+ private isEthEquivalent;
46
+ /**
47
+ * The registry's quote for a token, or null when it is not approved or has no calculator.
48
+ * Throws when the chain cannot be read, so a caller refuses for now rather than for good.
49
+ */
50
+ quote(address: string): Promise<RegistryQuote | null>;
51
+ private read;
52
+ /** A {@link PriceFor}: dollars per whole token for any approved pairing, null for the rest. */
53
+ priceFor: PriceFor;
54
+ /**
55
+ * The entry launch tooling needs before a coin is paid for: the token as the chain describes
56
+ * it, the price the gate will fix a round at, and the smallest per-wallet cap a flawless round
57
+ * fits under plus the operator's headroom. Null for a token the registry does not approve.
58
+ */
59
+ announce(address: `0x${string}`, options: AnnounceOptions): Promise<AnnouncedSpendToken | null>;
60
+ }
61
+ /**
62
+ * The smallest per-wallet cap under which a flawless round fits, in the token's base units, or
63
+ * null when no cap makes the economy work at this price. Checked against {@link resolveEconomy}
64
+ * rather than trusted, because that function is the one place the rule is written down.
65
+ */
66
+ export declare function minimumWalletCap(usdPerToken: number, decimals: number, options: Pick<AnnounceOptions, 'maxPointsPerPlayer' | 'pointsPerDollar'>): bigint | null;
67
+ /** A cap with the operator's percentage headroom, rounded down to base units. */
68
+ export declare function withHeadroom(cap: bigint, headroomPercent: number): bigint;
69
+ //# sourceMappingURL=registry-prices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-prices.d.ts","sourceRoot":"","sources":["../../src/chain/registry-prices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AAEhE,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AA4BlE,oFAAoF;AACpF,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;AAEhE,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;IAC/B,gFAAgF;IAChF,KAAK,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACtB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;CAChC;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,cAAc;IAOvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkE;IACzF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAGhB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB;IAMjD;;;OAGG;IACH,eAAe,IAAI,OAAO,CAAC,KAAK,MAAM,EAAE,GAAG,IAAI,CAAC;IAQhD,0FAA0F;IAC1F,OAAO,CAAC,eAAe;IAKvB;;;OAGG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;YAS7C,IAAI;IAuBlB,+FAA+F;IAC/F,QAAQ,EAAE,QAAQ,CAIhB;IAEF;;;;OAIG;IACG,QAAQ,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;CAkBtG;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,oBAAoB,GAAG,iBAAiB,CAAC,GACvE,MAAM,GAAG,IAAI,CAcf;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAKzE"}
@@ -0,0 +1,157 @@
1
+ import { formatUnits, parseAbi } from 'viem';
2
+ import { resolveEconomy, unitsPerToken } from '../economy.js';
3
+ /**
4
+ * Prices for any paired token the chain itself has approved, so a gate runs rounds on every
5
+ * pairing the protocol allows without anyone listing it first.
6
+ *
7
+ * A v1.3 PositionManager names its `PairedTokenRegistry`, and the registry names the price
8
+ * calculator each approved token was registered with — the same quote a launch uses to size a
9
+ * coin's starting price. That calculator answers "how many tokens is one ETH", and the operator's
10
+ * `USD_PER_ETH` turns that into dollars. Nothing here is typed by a person: an unapproved token has
11
+ * no calculator and is refused, exactly as the launch itself would be.
12
+ *
13
+ * Quotes are cached briefly. Adoption happens once per launch, so the cache protects the RPC from a
14
+ * burst of `/config/spend-tokens` reads by launch tooling, not from adoption itself. A quote that
15
+ * cannot be read throws, and the server answers adoption with 503 rather than a made-up price.
16
+ */
17
+ const managerAbi = parseAbi(['function pairedTokenRegistry() view returns (address)']);
18
+ const registryAbi = parseAbi([
19
+ 'function isApproved(address token) view returns (bool)',
20
+ 'function tokenConfig(address token) view returns ((bool approved, uint8 tokenType, uint8 decimals, address underlying, address feeEscrow, address priceCalculator, uint256 minDistribute, uint256 bidWallThreshold))',
21
+ ]);
22
+ const calculatorAbi = parseAbi(['function ethToPairedToken(uint256 ethAmount) view returns (uint256)']);
23
+ const erc20Abi = parseAbi(['function symbol() view returns (string)', 'function decimals() view returns (uint8)']);
24
+ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
25
+ export class RegistryPrices {
26
+ client;
27
+ options;
28
+ registry;
29
+ quotes = new Map();
30
+ ttlMs;
31
+ now;
32
+ constructor(client, options) {
33
+ this.client = client;
34
+ this.options = options;
35
+ this.ttlMs = options.ttlMs ?? 60_000;
36
+ this.now = options.now ?? Date.now;
37
+ }
38
+ /**
39
+ * The registry the manager names, or null for a manager that predates paired tokens. Read once:
40
+ * the address is immutable on chain, and a gate serves exactly one manager.
41
+ */
42
+ registryAddress() {
43
+ this.registry ??= this.client
44
+ .readContract({ address: this.options.positionManager, abi: managerAbi, functionName: 'pairedTokenRegistry' })
45
+ .then((address) => (address.toLowerCase() === ZERO_ADDRESS ? null : address))
46
+ .catch(() => null);
47
+ return this.registry;
48
+ }
49
+ /** ETH by any name is the operator's `USD_PER_ETH`; it is never asked of the registry. */
50
+ isEthEquivalent(address) {
51
+ const lower = address.toLowerCase();
52
+ return lower === ZERO_ADDRESS || (this.options.fleth !== undefined && lower === this.options.fleth.toLowerCase());
53
+ }
54
+ /**
55
+ * The registry's quote for a token, or null when it is not approved or has no calculator.
56
+ * Throws when the chain cannot be read, so a caller refuses for now rather than for good.
57
+ */
58
+ async quote(address) {
59
+ const key = address.toLowerCase();
60
+ const cached = this.quotes.get(key);
61
+ if (cached && this.now() - cached.at < this.ttlMs)
62
+ return cached.quote;
63
+ const quote = await this.read(address);
64
+ this.quotes.set(key, { quote, at: this.now() });
65
+ return quote;
66
+ }
67
+ async read(token) {
68
+ const registry = await this.registryAddress();
69
+ if (!registry)
70
+ return null;
71
+ const approved = await this.client.readContract({ address: registry, abi: registryAbi, functionName: 'isApproved', args: [token] });
72
+ if (!approved)
73
+ return null;
74
+ const config = await this.client.readContract({ address: registry, abi: registryAbi, functionName: 'tokenConfig', args: [token] });
75
+ const priceCalculator = config.priceCalculator;
76
+ if (!priceCalculator || priceCalculator.toLowerCase() === ZERO_ADDRESS)
77
+ return null;
78
+ const decimals = Number(config.decimals);
79
+ const perEth = await this.client.readContract({
80
+ address: priceCalculator,
81
+ abi: calculatorAbi,
82
+ functionName: 'ethToPairedToken',
83
+ args: [unitsPerToken(18)],
84
+ });
85
+ if (perEth <= 0n)
86
+ return null;
87
+ // String-based division: no binary float noise in a whole-token quote.
88
+ const tokensPerEth = Number(formatUnits(perEth, decimals));
89
+ if (!Number.isFinite(tokensPerEth) || tokensPerEth <= 0)
90
+ return null;
91
+ const usdPerToken = Number((this.options.usdPerEth / tokensPerEth).toPrecision(8));
92
+ return { usdPerToken, tokensPerEth, priceCalculator };
93
+ }
94
+ /** A {@link PriceFor}: dollars per whole token for any approved pairing, null for the rest. */
95
+ priceFor = async (token) => {
96
+ if (this.isEthEquivalent(token.address))
97
+ return null;
98
+ const quote = await this.quote(token.address);
99
+ return quote?.usdPerToken ?? null;
100
+ };
101
+ /**
102
+ * The entry launch tooling needs before a coin is paid for: the token as the chain describes
103
+ * it, the price the gate will fix a round at, and the smallest per-wallet cap a flawless round
104
+ * fits under plus the operator's headroom. Null for a token the registry does not approve.
105
+ */
106
+ async announce(address, options) {
107
+ if (this.isEthEquivalent(address))
108
+ return null;
109
+ const quote = await this.quote(address);
110
+ if (!quote)
111
+ return null;
112
+ const [symbol, decimals] = await Promise.all([
113
+ this.client.readContract({ address, abi: erc20Abi, functionName: 'symbol' }),
114
+ this.client.readContract({ address, abi: erc20Abi, functionName: 'decimals' }).then(Number),
115
+ ]);
116
+ const walletCap = minimumWalletCap(quote.usdPerToken, decimals, options);
117
+ if (walletCap === null)
118
+ return null;
119
+ return {
120
+ address,
121
+ symbol,
122
+ decimals,
123
+ usdPerToken: quote.usdPerToken,
124
+ walletCap: withHeadroom(walletCap, options.headroomPercent).toString(),
125
+ };
126
+ }
127
+ }
128
+ /**
129
+ * The smallest per-wallet cap under which a flawless round fits, in the token's base units, or
130
+ * null when no cap makes the economy work at this price. Checked against {@link resolveEconomy}
131
+ * rather than trusted, because that function is the one place the rule is written down.
132
+ */
133
+ export function minimumWalletCap(usdPerToken, decimals, options) {
134
+ const pointsPerToken = Math.round(usdPerToken * options.pointsPerDollar);
135
+ if (pointsPerToken <= 0)
136
+ return null;
137
+ const unitsPerPoint = unitsPerToken(decimals) / BigInt(pointsPerToken);
138
+ if (unitsPerPoint <= 0n)
139
+ return null;
140
+ const minimum = BigInt(Math.floor(options.maxPointsPerPlayer)) * unitsPerPoint;
141
+ const fit = resolveEconomy({
142
+ maxPointsPerPlayer: options.maxPointsPerPlayer,
143
+ walletCap: minimum,
144
+ pointsPerDollar: options.pointsPerDollar,
145
+ usdPerSpendToken: usdPerToken,
146
+ decimals,
147
+ });
148
+ return fit.ok ? minimum : null;
149
+ }
150
+ /** A cap with the operator's percentage headroom, rounded down to base units. */
151
+ export function withHeadroom(cap, headroomPercent) {
152
+ if (!Number.isSafeInteger(headroomPercent) || headroomPercent < 0) {
153
+ throw new Error('headroom percent must be a non-negative integer');
154
+ }
155
+ return (cap * BigInt(100 + headroomPercent)) / 100n;
156
+ }
157
+ //# sourceMappingURL=registry-prices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-prices.js","sourceRoot":"","sources":["../../src/chain/registry-prices.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"economy.d.ts","sourceRoot":"","sources":["../src/economy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,oGAAoG;AACpG,eAAO,MAAM,YAAY,KAAK,CAAC;AAK/B,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,MAAM,WAAW,YAAY;IAC3B,oFAAoF;IACpF,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,eAAe,EAAE,MAAM,CAAC;IACxB,qGAAqG;IACrG,gBAAgB,EAAE,MAAM,CAAC;IACzB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,OAAO;IACtB,+CAA+C;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,gGAAgG;IAChG,gBAAgB,EAAE,MAAM,CAAC;IACzB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC9B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,wBAAwB,EAAE,MAAM,CAAA;CAAE,CAAC;AASrE;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CA8EjE"}
1
+ {"version":3,"file":"economy.d.ts","sourceRoot":"","sources":["../src/economy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,oGAAoG;AACpG,eAAO,MAAM,YAAY,KAAK,CAAC;AAK/B,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,MAAM,WAAW,YAAY;IAC3B,oFAAoF;IACpF,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,eAAe,EAAE,MAAM,CAAC;IACxB,qGAAqG;IACrG,gBAAgB,EAAE,MAAM,CAAC;IACzB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,OAAO;IACtB,+CAA+C;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,gGAAgG;IAChG,gBAAgB,EAAE,MAAM,CAAC;IACzB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC9B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,wBAAwB,EAAE,MAAM,CAAA;CAAE,CAAC;AASrE;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAEjE"}
package/dist/economy.js CHANGED
@@ -40,6 +40,15 @@ function resolveInputs(input) {
40
40
  * goes and reads this file.
41
41
  */
42
42
  export function resolveEconomy(input) {
43
+ return evaluate(input, true);
44
+ }
45
+ /**
46
+ * The check itself. `suggest` is false while {@link minimumPointsPerDollar} is probing candidates:
47
+ * a refusal there must not go looking for a suggestion of its own, or a cap one unit short of
48
+ * fitting recurses until the stack gives out — which is how this function once took a gate down at
49
+ * boot instead of printing the number that fixes it.
50
+ */
51
+ function evaluate(input, suggest) {
43
52
  const { maxPointsPerPlayer, walletCap, pointsPerDollar } = input;
44
53
  const { usdPerSpendToken, decimals } = resolveInputs(input);
45
54
  if (!Number.isFinite(pointsPerDollar) || pointsPerDollar <= 0) {
@@ -82,7 +91,7 @@ export function resolveEconomy(input) {
82
91
  return {
83
92
  ok: false,
84
93
  problem: 'one point would be worth more than a whole spend token, which cannot be what was meant',
85
- suggestedPointsPerDollar: minimumPointsPerDollar(input),
94
+ suggestedPointsPerDollar: suggest ? minimumPointsPerDollar(input) : pointsPerDollar,
86
95
  };
87
96
  }
88
97
  const units = unitsPerToken(decimals);
@@ -99,7 +108,7 @@ export function resolveEconomy(input) {
99
108
  return {
100
109
  ok: false,
101
110
  problem: 'a perfect round would earn more than this launch lets one wallet spend',
102
- suggestedPointsPerDollar: minimumPointsPerDollar(input),
111
+ suggestedPointsPerDollar: suggest ? minimumPointsPerDollar(input) : pointsPerDollar,
103
112
  };
104
113
  }
105
114
  return {
@@ -131,7 +140,7 @@ function minimumPointsPerDollar(input) {
131
140
  const units = Number.isSafeInteger(decimals) && decimals >= 0 && decimals <= 36 ? unitsPerToken(decimals) : WEI_PER_ETH;
132
141
  let candidate = Math.ceil(Number(units / maxUnitsPerPoint) / usdPerSpendToken);
133
142
  for (let i = 0; i < 3; i++) {
134
- const result = resolveEconomy({ ...input, pointsPerDollar: candidate });
143
+ const result = evaluate({ ...input, pointsPerDollar: candidate }, false);
135
144
  if (result.ok)
136
145
  return candidate;
137
146
  candidate += 1;
@@ -1 +1 @@
1
- {"version":3,"file":"economy.js","sourceRoot":"","sources":["../src/economy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"economy.js","sourceRoot":"","sources":["../src/economy.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -30,11 +30,14 @@ export type { VerifiedPlayerJoin, VerifyPlayerJoinTicketOptions } from './player
30
30
  */
31
31
  export { startGate, resolveGateEnv } from './main.js';
32
32
  export type { ResolvedGateConfig, SpendTokenPricing, StartedGate, StartGateOverrides } from './main.js';
33
- export type { GateAnnouncement } from './server.js';
33
+ export type { GateAnnouncement, ServedGateAnnouncement } from './server.js';
34
+ export { GATE_MARKER, GATE_VERSION } from './version.js';
34
35
  export { NotSignedIn } from './sessions.js';
35
36
  export { DEPLOYMENTS, PAIRED_DEPLOYMENTS, deploymentFor } from './chain/chains.js';
36
37
  export type { FlaunchVariant, GateDeployment } from './chain/chains.js';
37
38
  export { POSITION_MANAGER_ROLE, assertSecureConfig } from './chain/secure.js';
39
+ export { RegistryPrices, minimumWalletCap, withHeadroom } from './chain/registry-prices.js';
40
+ export type { AnnounceOptions, RegistryPricesOptions, RegistryQuote, RegistryReader } from './chain/registry-prices.js';
38
41
  export { createGateReadiness } from './readiness.js';
39
42
  export type { GateReadinessOptions } from './readiness.js';
40
43
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -18,8 +18,10 @@ export { PLAYER_JOIN_TICKET_TTL_MS, verifyPlayerJoinTicket } from './player-join
18
18
  * gate (see DEPLOY.md), and the pieces below it stay exported for anyone wiring their own.
19
19
  */
20
20
  export { startGate, resolveGateEnv } from './main.js';
21
+ export { GATE_MARKER, GATE_VERSION } from './version.js';
21
22
  export { NotSignedIn } from './sessions.js';
22
23
  export { DEPLOYMENTS, PAIRED_DEPLOYMENTS, deploymentFor } from './chain/chains.js';
23
24
  export { POSITION_MANAGER_ROLE, assertSecureConfig } from './chain/secure.js';
25
+ export { RegistryPrices, minimumWalletCap, withHeadroom } from './chain/registry-prices.js';
24
26
  export { createGateReadiness } from './readiness.js';
25
27
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EACL,MAAM,EACN,0BAA0B,EAC1B,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAarB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAUxD,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAG7F;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGtD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EACL,MAAM,EACN,0BAA0B,EAC1B,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAarB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAUxD,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAG7F;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGtD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG5F,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/main.d.ts CHANGED
@@ -45,6 +45,12 @@ export interface ResolvedGateConfig {
45
45
  * refused at adoption — the gate does not guess a token's price.
46
46
  */
47
47
  spendTokens: ReadonlyMap<string, SpendTokenPricing>;
48
+ /**
49
+ * Percent added over the smallest cap a flawless round fits under when the gate sizes a cap for a
50
+ * registry-priced pairing (`/config/spend-tokens/:address`). Prices move between the quote and the
51
+ * launch; this is the room left for that.
52
+ */
53
+ pairedTokenCapHeadroomPercent: number;
48
54
  /** May lift the gate early or rotate the signer on-chain. Defaults to the signing key's address. */
49
55
  settler: `0x${string}` | null;
50
56
  }
@@ -82,7 +88,10 @@ export interface SpendTokenPricing {
82
88
  * POINTS_PER_DOLLAR default 100
83
89
  * USD_PER_ETH default 3000; fractional allowed
84
90
  * SPEND_TOKENS optional JSON array of { address, usdPerToken, walletCap } — the non-ETH
85
- * paired tokens this gate runs rounds on. Unlisted tokens are refused.
91
+ * paired tokens this gate runs rounds on. Pins a price the registry
92
+ * would otherwise quote; tokens neither here nor approved on the
93
+ * manager's PairedTokenRegistry are refused.
94
+ * PAIRED_TOKEN_CAP_HEADROOM_PERCENT default 25; headroom on caps sized for registry-priced pairings
86
95
  */
87
96
  export declare function resolveGateEnv(env: Env): ResolvedGateConfig;
88
97
  export interface StartedGate {
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAiD,KAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAA+D,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AASzG,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGvE;;;;;;;;;;;;GAYG;AAEH,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,KAAK,MAAM,EAAE,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,YAAY,EAAE,MAAM,CAAC;IACrB,kGAAkG;IAClG,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,cAAc,CAAC;IAC3B,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,0FAA0F;IAC1F,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACpD,oGAAoG;IACpG,OAAO,EAAE,KAAK,MAAM,EAAE,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB;AAuED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,kBAAkB,CAgF3D;AA4BD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,eAAe,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,MAAM,EAAE,KAAK,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,qEAAqE;IACrE,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,aAAa,CAAC,EAAE,QAAQ,CAAC;CAC1B;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAClF,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,EACtE,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,kBAAuB,GACjC,OAAO,CAAC,WAAW,CAAC,CAoHtB"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAiD,KAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAA+D,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AASzG,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIvE;;;;;;;;;;;;GAYG;AAEH,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,KAAK,MAAM,EAAE,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,YAAY,EAAE,MAAM,CAAC;IACrB,kGAAkG;IAClG,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,cAAc,CAAC;IAC3B,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,0FAA0F;IAC1F,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACpD;;;;OAIG;IACH,6BAA6B,EAAE,MAAM,CAAC;IACtC,oGAAoG;IACpG,OAAO,EAAE,KAAK,MAAM,EAAE,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB;AAuED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,kBAAkB,CAiF3D;AA8BD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,eAAe,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,MAAM,EAAE,KAAK,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,qEAAqE;IACrE,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,aAAa,CAAC,EAAE,QAAQ,CAAC;CAC1B;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAClF,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,EACtE,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,kBAAuB,GACjC,OAAO,CAAC,WAAW,CAAC,CAyItB"}
package/dist/main.js CHANGED
@@ -12,6 +12,7 @@ import { migrate } from './store.js';
12
12
  import { resolveEconomy } from './economy.js';
13
13
  import { deploymentFor } from './chain/chains.js';
14
14
  import { assertSecureConfig } from './chain/secure.js';
15
+ import { RegistryPrices } from './chain/registry-prices.js';
15
16
  function required(env, name) {
16
17
  const value = env[name];
17
18
  if (!value)
@@ -114,7 +115,10 @@ function address(env, name) {
114
115
  * POINTS_PER_DOLLAR default 100
115
116
  * USD_PER_ETH default 3000; fractional allowed
116
117
  * SPEND_TOKENS optional JSON array of { address, usdPerToken, walletCap } — the non-ETH
117
- * paired tokens this gate runs rounds on. Unlisted tokens are refused.
118
+ * paired tokens this gate runs rounds on. Pins a price the registry
119
+ * would otherwise quote; tokens neither here nor approved on the
120
+ * manager's PairedTokenRegistry are refused.
121
+ * PAIRED_TOKEN_CAP_HEADROOM_PERCENT default 25; headroom on caps sized for registry-priced pairings
118
122
  */
119
123
  export function resolveGateEnv(env) {
120
124
  const chainId = Number(required(env, 'CHAIN_ID'));
@@ -186,6 +190,7 @@ export function resolveGateEnv(env) {
186
190
  pointsPerDollar: integer(env, 'POINTS_PER_DOLLAR', 100),
187
191
  usdPerEth: positiveNumber(env, 'USD_PER_ETH', 3_000),
188
192
  spendTokens: spendTokens(env),
193
+ pairedTokenCapHeadroomPercent: integer(env, 'PAIRED_TOKEN_CAP_HEADROOM_PERCENT', 25),
189
194
  settler: address(env, 'SETTLER'),
190
195
  };
191
196
  }
@@ -198,9 +203,11 @@ function isEthEquivalent(token, fleth) {
198
203
  * The price list a running gate answers adoption with.
199
204
  *
200
205
  * An override (an oracle, a test) is asked first; the env map second; ETH and its wrapper are the
201
- * operator's `USD_PER_ETH`; anything else is unpriced and the launch is refused.
206
+ * operator's `USD_PER_ETH`; then the manager's own PairedTokenRegistry, which prices every token the
207
+ * protocol has approved through the calculator it was registered with. Only a token none of them
208
+ * know is unpriced, and that launch is refused — it could not have been launched either.
202
209
  */
203
- function priceList(config, override) {
210
+ function priceList(config, override, registry) {
204
211
  return async (token) => {
205
212
  if (override) {
206
213
  const quoted = await override(token);
@@ -212,7 +219,7 @@ function priceList(config, override) {
212
219
  return listed.usdPerToken;
213
220
  if (isEthEquivalent(token, config.deployment.fleth))
214
221
  return config.usdPerEth;
215
- return null;
222
+ return registry.priceFor(token);
216
223
  };
217
224
  }
218
225
  export async function startGate(game, gameConfig, overrides = {}) {
@@ -271,6 +278,15 @@ export async function startGate(game, gameConfig, overrides = {}) {
271
278
  walletCap: pricing.walletCap.toString(),
272
279
  });
273
280
  }
281
+ // Every pairing the protocol approves, priced by the calculator it was registered with. The
282
+ // registry is read from the manager, so nothing is configured and nothing goes stale when a new
283
+ // token is approved: the next launch on it is adopted like any other.
284
+ const registryPrices = new RegistryPrices(client, {
285
+ positionManager: config.deployment.positionManager,
286
+ ...(config.deployment.fleth ? { fleth: config.deployment.fleth } : {}),
287
+ usdPerEth: config.usdPerEth,
288
+ });
289
+ const pairedTokenRegistry = await registryPrices.registryAddress();
274
290
  const pool = new pg.Pool({ connectionString: config.databaseUrl });
275
291
  await migrate(pool);
276
292
  const ledger = new Ledger(pool);
@@ -291,6 +307,7 @@ export async function startGate(game, gameConfig, overrides = {}) {
291
307
  gateEndsAtGraceS: config.gateEndsAtGraceS,
292
308
  flaunchVariant: config.deployment.flaunchVariant,
293
309
  ...(announcedSpendTokens.length > 0 ? { spendTokens: announcedSpendTokens } : {}),
310
+ ...(pairedTokenRegistry ? { pairedTokenRegistry } : {}),
294
311
  requiresEoa: false,
295
312
  accepting: true,
296
313
  publicLaunchesOpen: true,
@@ -302,7 +319,18 @@ export async function startGate(game, gameConfig, overrides = {}) {
302
319
  config: gameConfig,
303
320
  pointsPerDollar: config.pointsPerDollar,
304
321
  usdPerEth: config.usdPerEth,
305
- priceFor: priceList(config, overrides.priceProvider),
322
+ priceFor: priceList(config, overrides.priceProvider, registryPrices),
323
+ announceSpendToken: async (address) => {
324
+ // An operator-pinned token is announced exactly as pinned; anything else is the registry's word.
325
+ const pinned = announcedSpendTokens.find((entry) => entry.address.toLowerCase() === address.toLowerCase());
326
+ if (pinned)
327
+ return pinned;
328
+ return registryPrices.announce(address, {
329
+ maxPointsPerPlayer,
330
+ pointsPerDollar: config.pointsPerDollar,
331
+ headroomPercent: config.pairedTokenCapHeadroomPercent,
332
+ });
333
+ },
306
334
  sessions: new Sessions(config.sessionSecret, config.signInDomain, config.gateOrigin),
307
335
  claims: new Claims(pool, ledger, signer),
308
336
  discovery: new Discovery(client, {