@dust-dice/verifier 0.4.0 → 0.4.2

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.
@@ -0,0 +1,5 @@
1
+ import { type NetworkConfig } from '@dust-dice/api/node';
2
+ /** UNDEPLOYED (the local devnet) unless the MIDNIGHT_* environment variables say otherwise. */
3
+ export declare const NETWORK: NetworkConfig;
4
+ export declare const MANAGED_TABLE: string;
5
+ export declare const MANAGED_LOBBY: string;
package/dist/config.js ADDED
@@ -0,0 +1,29 @@
1
+ // Copyright (C) Shielded Technologies
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * The verifier's configuration: which network to read, and where the compiled contract lives.
5
+ * Nothing here is a secret or a game parameter — the verifier only READS the chain.
6
+ */
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import { createRequire } from 'node:module';
10
+ import { resolveNetwork } from '@dust-dice/api/node';
11
+ const require = createRequire(import.meta.url);
12
+ /** UNDEPLOYED (the local devnet) unless the MIDNIGHT_* environment variables say otherwise. */
13
+ export const NETWORK = resolveNetwork();
14
+ const CONTRACT_ROOT = path.dirname(require.resolve('@dust-dice/contract/package.json'));
15
+ /**
16
+ * Where `@dust-dice/contract` keeps compactc's output for the two deployables. The PUBLISHED
17
+ * package ships them under `dist/managed` (keys and ZKIR for table and lobby only); a source
18
+ * checkout that has compiled but not built has them under `src/managed`. Prefer the built copy,
19
+ * which is what a consumer installs, and fall back to the source tree for development.
20
+ */
21
+ const managedRoot = (() => {
22
+ const built = path.join(CONTRACT_ROOT, 'dist', 'managed');
23
+ return fs.existsSync(path.join(built, 'table', 'keys'))
24
+ ? built
25
+ : path.join(CONTRACT_ROOT, 'src', 'managed');
26
+ })();
27
+ export const MANAGED_TABLE = path.join(managedRoot, 'table');
28
+ export const MANAGED_LOBBY = path.join(managedRoot, 'lobby');
29
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AACtC;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAC;AAEzE,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,+FAA+F;AAC/F,MAAM,CAAC,MAAM,OAAO,GAAkB,cAAc,EAAE,CAAC;AAEvD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,CAAC;AACxF;;;;;GAKG;AACH,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1D,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;AACjD,CAAC,CAAC,EAAE,CAAC;AACL,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * The `compiledContract` values `deployContract`/`findDeployedContract` take, and one-shot
3
+ * reads of a table's public ledger.
4
+ *
5
+ * On midnight-js 5.x a `compiledContract` is NOT a bare `new Contract(witnesses)`:
6
+ * `deployContract` calls compact-js's `createContract`, which reads a hidden `CompactContext`
7
+ * off the value and needs `.ctor` and `.witnesses` on it. Passing a Contract instance fails
8
+ * deep inside proving with `TypeError: Cannot read properties of undefined (reading 'ctor')`,
9
+ * which names neither the argument nor the missing wrapper. The wrapper is
10
+ * `CompiledContract.make(tag, Ctor).pipe(...)`; both contracts here declare witnesses, so the
11
+ * combinator is `withWitnesses` (`withVacantWitnesses` is for contracts that declare none).
12
+ */
13
+ import { CompiledContract } from '@midnight-ntwrk/midnight-js-protocol/compact-js';
14
+ import { Table, Lobby, type TablePrivateState, type LobbyPrivateState } from '@dust-dice/contract';
15
+ export { Table, Lobby };
16
+ /**
17
+ * The exported circuit names, spelled out.
18
+ *
19
+ * `createProviders` is generic in this and it MUST be instantiated with the concrete union, not
20
+ * left to infer `string`: midnight-js ties a provider's circuit-id type to the contract's own
21
+ * `ProvableCircuitId`, so a `string` here fails every `deployContract`/`findDeployedContract`
22
+ * overload with "Type 'string' is not assignable to type 'ProvableCircuitId<...>'" -- an error
23
+ * that points at the providers argument and says nothing about the type parameter that caused
24
+ * it.
25
+ */
26
+ export type TableCircuitId = 'join' | 'playerMove' | 'resolveRoll1' | 'resolveReroll' | 'closeRound' | 'eliminate' | 'settle' | 'redeem' | 'abortTable';
27
+ export type LobbyCircuitId = 'openTableAt' | 'tableFilled';
28
+ export declare const CompiledTableContract: CompiledContract.CompiledContract<Table.Contract<TablePrivateState, Table.Witnesses<TablePrivateState>>, TablePrivateState, never>;
29
+ export declare const CompiledLobbyContract: CompiledContract.CompiledContract<Lobby.Contract<LobbyPrivateState, Lobby.Witnesses<LobbyPrivateState>>, LobbyPrivateState, never>;
30
+ export type TableLedger = Table.Ledger;
31
+ export type LobbyLedger = Lobby.Ledger;
32
+ /**
33
+ * Read a table's ledger with a ONE-SHOT query.
34
+ *
35
+ * Deliberately not `contractStateObservable`: that observable misses rapid successive updates
36
+ * and its first emission may predate the write being checked, so every read-after-write in this
37
+ * driver -- and there is one after almost every transaction -- has to use `queryContractState`.
38
+ * (bugs-found.md §0 #10; the same reason probes/gate0/src/step.ts reads this way.)
39
+ *
40
+ * `blockHeight` pins the read to a past block, which is what the chain-only verifier walks the
41
+ * game with.
42
+ */
43
+ export declare function readTableLedger(address: string, blockHeight?: number): Promise<TableLedger>;
44
+ export declare function readLobbyLedger(address: string): Promise<LobbyLedger>;
45
+ /** `Dice` as the plain five-element array everything else in this repo speaks. */
46
+ export declare function diceToArray(d: Table.Dice): number[];
47
+ /** Rounds per seat: 0..12, thirteen of them, one category each. `roundCount()`. */
48
+ export declare const ROUND_COUNT = 13;
49
+ /** The last round a seat plays. Completing it completes the scorecard. */
50
+ export declare const FINAL_ROUND = 12;
51
+ /** `playerMove` kinds. */
52
+ export declare const MOVE_OPEN = 0;
53
+ export declare const MOVE_HOLD = 1;
54
+ export declare const MOVE_SCORE = 2;
55
+ /**
56
+ * `seatTurn.stage`.
57
+ *
58
+ * EVEN STAGES ARE OWED BY THE PLAYER, ODD ONES BY THE OPERATOR. That split is what the driver
59
+ * dispatches on and what `eliminate` and `abortTable` divide on in the contract.
60
+ */
61
+ export declare const STAGE: {
62
+ readonly idle: 0;
63
+ readonly awaitRoll1: 1;
64
+ readonly rolled1: 2;
65
+ readonly awaitRoll2: 3;
66
+ readonly rolled2: 4;
67
+ readonly awaitRoll3: 5;
68
+ readonly rolled3: 6;
69
+ };
70
+ /** Is this seat's next move the player's? */
71
+ export declare const playerOwes: (stage: number) => boolean;
72
+ /** The canonical "no mask" sentinel every `playerMove` kind but `hold` must carry. */
73
+ export declare const NO_MASK: boolean[];
74
+ /** The canonical "no entropy" sentinel every kind but `open` must carry. */
75
+ export declare const ZERO_BYTES32: () => Uint8Array;
76
+ /** One seat's position, as the driver reads it off the ledger. */
77
+ export interface SeatView {
78
+ seat: number;
79
+ /** The next round this seat owes; `ROUND_COUNT` means finished or eliminated. */
80
+ round: number;
81
+ stage: number;
82
+ eliminated: boolean;
83
+ /** The dice as of the most recent resolved roll of the current turn. */
84
+ roll: number[];
85
+ }
86
+ export declare function seatView(led: TableLedger, seat: number): SeatView;
87
+ /** Every seated slot's view, in seat order. */
88
+ export declare function seatViews(led: TableLedger): SeatView[];
89
+ /**
90
+ * The penalty split `eliminate` requires: `q * 13 + rem == tier * (round + 1)`, `rem < 13`.
91
+ *
92
+ * Compact has no division, so the caller supplies the quotient and remainder and the circuit
93
+ * checks the Euclidean identity -- which has exactly one solution, so supplying them grants no
94
+ * discretion. `round + 1` reconciles the contract's 0-based rounds with the design note's
95
+ * 1..13 numbering: a seat that never played at all forfeits a thirteenth, not nothing.
96
+ */
97
+ export declare function penaltySplit(tier: bigint, round: number): {
98
+ q: bigint;
99
+ rem: bigint;
100
+ };
101
+ /** The per-seat 1% rake on `tier` that `abortTable` requires, on every path. */
102
+ export declare function perSeatRake(tier: bigint): {
103
+ q: bigint;
104
+ rem: bigint;
105
+ };
@@ -0,0 +1,121 @@
1
+ // Copyright (C) Shielded Technologies
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * The `compiledContract` values `deployContract`/`findDeployedContract` take, and one-shot
5
+ * reads of a table's public ledger.
6
+ *
7
+ * On midnight-js 5.x a `compiledContract` is NOT a bare `new Contract(witnesses)`:
8
+ * `deployContract` calls compact-js's `createContract`, which reads a hidden `CompactContext`
9
+ * off the value and needs `.ctor` and `.witnesses` on it. Passing a Contract instance fails
10
+ * deep inside proving with `TypeError: Cannot read properties of undefined (reading 'ctor')`,
11
+ * which names neither the argument nor the missing wrapper. The wrapper is
12
+ * `CompiledContract.make(tag, Ctor).pipe(...)`; both contracts here declare witnesses, so the
13
+ * combinator is `withWitnesses` (`withVacantWitnesses` is for contracts that declare none).
14
+ */
15
+ import { CompiledContract } from '@midnight-ntwrk/midnight-js-protocol/compact-js';
16
+ import { indexerPublicDataProvider } from '@midnight-ntwrk/midnight-js-indexer-public-data-provider';
17
+ import { Table, Lobby, tableWitnesses, lobbyWitnesses, } from '@dust-dice/contract';
18
+ import { NETWORK } from "./config.js";
19
+ export { Table, Lobby };
20
+ export const CompiledTableContract = CompiledContract.make('Table', (Table.Contract)).pipe(CompiledContract.withWitnesses(tableWitnesses), CompiledContract.withCompiledFileAssets('./table'));
21
+ export const CompiledLobbyContract = CompiledContract.make('Lobby', (Lobby.Contract)).pipe(CompiledContract.withWitnesses(lobbyWitnesses), CompiledContract.withCompiledFileAssets('./lobby'));
22
+ /**
23
+ * Read a table's ledger with a ONE-SHOT query.
24
+ *
25
+ * Deliberately not `contractStateObservable`: that observable misses rapid successive updates
26
+ * and its first emission may predate the write being checked, so every read-after-write in this
27
+ * driver -- and there is one after almost every transaction -- has to use `queryContractState`.
28
+ * (bugs-found.md §0 #10; the same reason probes/gate0/src/step.ts reads this way.)
29
+ *
30
+ * `blockHeight` pins the read to a past block, which is what the chain-only verifier walks the
31
+ * game with.
32
+ */
33
+ export async function readTableLedger(address, blockHeight) {
34
+ const pdp = indexerPublicDataProvider(NETWORK.indexer, NETWORK.indexerWS);
35
+ const state = blockHeight === undefined
36
+ ? await pdp.queryContractState(address)
37
+ : await pdp.queryContractState(address, { type: 'blockHeight', blockHeight });
38
+ if (!state) {
39
+ throw new Error(`no contract state at ${address}${blockHeight === undefined ? '' : ` @ block ${blockHeight}`}`);
40
+ }
41
+ return Table.ledger(state.data);
42
+ }
43
+ export async function readLobbyLedger(address) {
44
+ const pdp = indexerPublicDataProvider(NETWORK.indexer, NETWORK.indexerWS);
45
+ const state = await pdp.queryContractState(address);
46
+ if (!state)
47
+ throw new Error(`no contract state at ${address}`);
48
+ return Lobby.ledger(state.data);
49
+ }
50
+ /** `Dice` as the plain five-element array everything else in this repo speaks. */
51
+ export function diceToArray(d) {
52
+ return [d.d0, d.d1, d.d2, d.d3, d.d4].map(Number);
53
+ }
54
+ // ---------------------------------------------------------------------------------------
55
+ // The shape of a game, restated for the driver and the verifier
56
+ // ---------------------------------------------------------------------------------------
57
+ //
58
+ // These mirror `table.compact` and are restated here rather than imported because the generated
59
+ // bindings spell them as plain `Uint<8>` values (they are not Compact `enum`s) and because both
60
+ // the driver and the chain-only verifier need them. See docs/table-interface.md.
61
+ /** Rounds per seat: 0..12, thirteen of them, one category each. `roundCount()`. */
62
+ export const ROUND_COUNT = 13;
63
+ /** The last round a seat plays. Completing it completes the scorecard. */
64
+ export const FINAL_ROUND = 12;
65
+ /** `playerMove` kinds. */
66
+ export const MOVE_OPEN = 0;
67
+ export const MOVE_HOLD = 1;
68
+ export const MOVE_SCORE = 2;
69
+ /**
70
+ * `seatTurn.stage`.
71
+ *
72
+ * EVEN STAGES ARE OWED BY THE PLAYER, ODD ONES BY THE OPERATOR. That split is what the driver
73
+ * dispatches on and what `eliminate` and `abortTable` divide on in the contract.
74
+ */
75
+ export const STAGE = {
76
+ idle: 0,
77
+ awaitRoll1: 1,
78
+ rolled1: 2,
79
+ awaitRoll2: 3,
80
+ rolled2: 4,
81
+ awaitRoll3: 5,
82
+ rolled3: 6,
83
+ };
84
+ /** Is this seat's next move the player's? */
85
+ export const playerOwes = (stage) => stage % 2 === 0;
86
+ /** The canonical "no mask" sentinel every `playerMove` kind but `hold` must carry. */
87
+ export const NO_MASK = [false, false, false, false, false];
88
+ /** The canonical "no entropy" sentinel every kind but `open` must carry. */
89
+ export const ZERO_BYTES32 = () => new Uint8Array(32);
90
+ export function seatView(led, seat) {
91
+ const prog = led.seatProgress.lookup(BigInt(seat));
92
+ const turn = led.seatTurn.lookup(BigInt(seat));
93
+ return {
94
+ seat,
95
+ round: Number(prog.round),
96
+ stage: Number(turn.stage),
97
+ eliminated: prog.eliminated,
98
+ roll: diceToArray(turn.roll),
99
+ };
100
+ }
101
+ /** Every seated slot's view, in seat order. */
102
+ export function seatViews(led) {
103
+ return Array.from({ length: Number(led.seatCount) }, (_, s) => seatView(led, s));
104
+ }
105
+ /**
106
+ * The penalty split `eliminate` requires: `q * 13 + rem == tier * (round + 1)`, `rem < 13`.
107
+ *
108
+ * Compact has no division, so the caller supplies the quotient and remainder and the circuit
109
+ * checks the Euclidean identity -- which has exactly one solution, so supplying them grants no
110
+ * discretion. `round + 1` reconciles the contract's 0-based rounds with the design note's
111
+ * 1..13 numbering: a seat that never played at all forfeits a thirteenth, not nothing.
112
+ */
113
+ export function penaltySplit(tier, round) {
114
+ const numer = tier * BigInt(round + 1);
115
+ return { q: numer / 13n, rem: numer % 13n };
116
+ }
117
+ /** The per-seat 1% rake on `tier` that `abortTable` requires, on every path. */
118
+ export function perSeatRake(tier) {
119
+ return { q: tier / 100n, rem: tier % 100n };
120
+ }
121
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The read side of Dust Dice, for anyone: compiled-contract handles, indexer queries, and the
3
+ * network/artifact configuration. The verifier itself is the package's `bin` (`dust-dice-verify`)
4
+ * and is deliberately not re-exported here — importing it runs it.
5
+ */
6
+ export * from './config.ts';
7
+ export * from './contracts.ts';
8
+ export * from './indexer.ts';
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ // Copyright (C) Shielded Technologies
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * The read side of Dust Dice, for anyone: compiled-contract handles, indexer queries, and the
5
+ * network/artifact configuration. The verifier itself is the package's `bin` (`dust-dice-verify`)
6
+ * and is deliberately not re-exported here — importing it runs it.
7
+ */
8
+ export * from "./config.js";
9
+ export * from "./contracts.js";
10
+ export * from "./indexer.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AACtC;;;;GAIG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,89 @@
1
+ export interface GqlUnshieldedUtxo {
2
+ owner: string;
3
+ tokenType: string;
4
+ value: string;
5
+ intentHash: string;
6
+ outputIndex: number;
7
+ registeredForDustGeneration: boolean;
8
+ }
9
+ export interface GqlTransaction {
10
+ hash: string;
11
+ /** Hex of the whole transaction as the node saw it. `length / 2` is the size it checked. */
12
+ raw: string;
13
+ block: {
14
+ height: number;
15
+ timestamp: string;
16
+ };
17
+ unshieldedCreatedOutputs: GqlUnshieldedUtxo[];
18
+ unshieldedSpentOutputs: GqlUnshieldedUtxo[];
19
+ }
20
+ /** One entry in a contract's public history. `entryPoint` is absent on the deploy. */
21
+ export interface ContractAction {
22
+ kind: 'ContractDeploy' | 'ContractCall' | 'ContractUpdate';
23
+ entryPoint?: string;
24
+ txHash: string;
25
+ blockHeight: number;
26
+ blockTimestamp: number;
27
+ }
28
+ /** The native (NIGHT) token type is 32 zero bytes. Matches Compact's `nativeToken()`. */
29
+ export declare const NATIVE_TOKEN_HEX: string;
30
+ export declare function sumNative(utxos: GqlUnshieldedUtxo[]): bigint;
31
+ export declare function sumNativeFor(utxos: GqlUnshieldedUtxo[], owner: string): bigint;
32
+ /**
33
+ * The contract's own unshielded balances as the LEDGER sees them, keyed by token-type hex.
34
+ *
35
+ * `unshieldedBalances` hangs off `ContractAction`, NOT off `Contract` -- `contract(address)`
36
+ * returns a `Contract` whose only fields are address/state/maintenanceAuthority/actions.
37
+ * `contractAction(address)` returns the latest action, which is what carries the running
38
+ * balances, and all three action variants declare the field so it selects on the interface.
39
+ */
40
+ export declare function contractUnshieldedBalances(address: string): Promise<Record<string, bigint>>;
41
+ export declare function nativeBalance(balances: Record<string, bigint>): bigint;
42
+ /**
43
+ * One transaction by hash, with its UTXO deltas and its raw bytes.
44
+ *
45
+ * Polls: the indexer trails the node slightly, so a hash returned by `submitTransaction` is not
46
+ * necessarily queryable the same instant.
47
+ */
48
+ export declare function transactionByHash(hash: string, { attempts, delayMs }?: {
49
+ attempts?: number | undefined;
50
+ delayMs?: number | undefined;
51
+ }): Promise<GqlTransaction>;
52
+ /** Byte size of a transaction as the node measured it, from the indexer's `raw` hex. */
53
+ export declare function transactionBytes(tx: GqlTransaction): number;
54
+ /**
55
+ * The node's dismiss-time allowance for a transaction of `bytes`, in milliseconds.
56
+ *
57
+ * `max(min_time_to_dismiss, time_to_dismiss_per_byte x size)` with ledger-9.1.0.0-rc.3's
58
+ * `INITIAL_LIMITS`: 15.000 ms and 0.002 ms/byte. A transaction is admissible only if this
59
+ * exceeds its dismiss cost, which is ~15.97 ms of fixed cryptographic constants -- hence the
60
+ * ~7,984-byte floor (docs/gate0-report.md).
61
+ */
62
+ export declare const allowanceMs: (bytes: number) => number;
63
+ /** The floor a contract call must clear to be admitted at all, in bytes. */
64
+ export declare const ADMISSION_FLOOR_BYTES = 7984;
65
+ /**
66
+ * A contract's whole public history, oldest first.
67
+ *
68
+ * This is the ONLY thing `verify.ts` is given beyond the table's address: every join, every
69
+ * turn and the settlement are recovered from these actions and the contract states they point
70
+ * at. The indexer returns them newest-first, so they are reversed here.
71
+ */
72
+ export declare function contractActions(address: string, limit?: number): Promise<ContractAction[]>;
73
+ /** Current chain tip, for sanity-checking that blocks are being produced. */
74
+ export declare function tip(): Promise<{
75
+ height: number;
76
+ timestamp: number;
77
+ }>;
78
+ /**
79
+ * The `now` a state-advancing circuit should declare, in seconds since the epoch.
80
+ *
81
+ * Read off the CHAIN's latest block rather than from the local wall clock, and that choice is
82
+ * deliberate. `stampTime` traps the declared value in `(blockTime - 600, blockTime]`
83
+ * (table.compact, decision 5), so `now` must not exceed the block time of the block the
84
+ * transaction lands in. The tip's timestamp is by construction less than or equal to that of
85
+ * any later block, so it always satisfies the upper bound, and the transaction lands a few
86
+ * blocks later -- far inside the 600 s slack. A local clock a second fast would fail
87
+ * `blockTimeGte` instead, with an assertion message about time that says nothing about clocks.
88
+ */
89
+ export declare function chainNowSecs(): Promise<bigint>;
@@ -0,0 +1,173 @@
1
+ // Copyright (C) Shielded Technologies
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Direct indexer GraphQL access, for evidence the wallet cannot be asked to provide.
5
+ *
6
+ * The wallet facade's own `state().unshielded.balances` is the natural place to read a balance,
7
+ * but it is the same component that built the transactions -- so on its own it is a weak witness
8
+ * that custody really happened, and during Gate 0 it misreported a pre-stake balance by
9
+ * 4,900,000 in exactly this situation (docs/bugs-found.md §9). PER-TRANSACTION UTXO MOVEMENT IS
10
+ * THE ONLY TRUSTWORTHY MEASURE, and it is what these queries read:
11
+ *
12
+ * - `contractAction(address){ unshieldedBalances }` what the LEDGER says the contract holds
13
+ * - `transactions(offset:{hash}){ unshieldedCreatedOutputs / unshieldedSpentOutputs }`
14
+ * who actually received or spent what, with
15
+ * `registeredForDustGeneration` per created
16
+ * UTXO (the designation question)
17
+ * - `transactions(offset:{hash}){ raw }` the transaction's byte size, which is what
18
+ * the `OutsideTimeToDismiss` admission check
19
+ * measures
20
+ * - `contract(address){ actions }` the table's whole public history, which is
21
+ * all the chain-only verifier is given
22
+ *
23
+ * There is no user-address balance query in this indexer's schema (checked by introspecting
24
+ * `__schema.queryType.fields`: only `bridgeBalance(address)` takes an address, and that is the
25
+ * Cardano bridge, not NIGHT), so per-address totals are derived from the UTXO sets above.
26
+ */
27
+ import { NETWORK } from "./config.js";
28
+ async function gql(query, variables = {}) {
29
+ const res = await fetch(NETWORK.indexer, {
30
+ method: 'POST',
31
+ headers: { 'Content-Type': 'application/json' },
32
+ body: JSON.stringify({ query, variables }),
33
+ });
34
+ if (!res.ok)
35
+ throw new Error(`indexer HTTP ${res.status}: ${await res.text()}`);
36
+ const body = (await res.json());
37
+ if (body.errors?.length) {
38
+ throw new Error(`indexer GraphQL: ${body.errors.map((e) => e.message).join('; ')}`);
39
+ }
40
+ if (!body.data)
41
+ throw new Error('indexer returned no data');
42
+ return body.data;
43
+ }
44
+ /** The native (NIGHT) token type is 32 zero bytes. Matches Compact's `nativeToken()`. */
45
+ export const NATIVE_TOKEN_HEX = '00'.repeat(32);
46
+ const isNative = (u) => u.tokenType.replace(/^0x/, '').toLowerCase() === NATIVE_TOKEN_HEX;
47
+ export function sumNative(utxos) {
48
+ return utxos.filter(isNative).reduce((acc, u) => acc + BigInt(u.value), 0n);
49
+ }
50
+ export function sumNativeFor(utxos, owner) {
51
+ return sumNative(utxos.filter((u) => u.owner === owner));
52
+ }
53
+ /**
54
+ * The contract's own unshielded balances as the LEDGER sees them, keyed by token-type hex.
55
+ *
56
+ * `unshieldedBalances` hangs off `ContractAction`, NOT off `Contract` -- `contract(address)`
57
+ * returns a `Contract` whose only fields are address/state/maintenanceAuthority/actions.
58
+ * `contractAction(address)` returns the latest action, which is what carries the running
59
+ * balances, and all three action variants declare the field so it selects on the interface.
60
+ */
61
+ export async function contractUnshieldedBalances(address) {
62
+ const data = await gql(`query ($address: HexEncoded!) {
63
+ contractAction(address: $address) { unshieldedBalances { tokenType amount } }
64
+ }`, { address });
65
+ const out = {};
66
+ for (const b of data.contractAction?.unshieldedBalances ?? [])
67
+ out[b.tokenType] = BigInt(b.amount);
68
+ return out;
69
+ }
70
+ export function nativeBalance(balances) {
71
+ for (const [k, v] of Object.entries(balances)) {
72
+ if (k.replace(/^0x/, '').toLowerCase() === NATIVE_TOKEN_HEX)
73
+ return v;
74
+ }
75
+ return 0n;
76
+ }
77
+ /**
78
+ * One transaction by hash, with its UTXO deltas and its raw bytes.
79
+ *
80
+ * Polls: the indexer trails the node slightly, so a hash returned by `submitTransaction` is not
81
+ * necessarily queryable the same instant.
82
+ */
83
+ export async function transactionByHash(hash, { attempts = 40, delayMs = 1000 } = {}) {
84
+ const q = `query ($hash: HexEncoded!) {
85
+ transactions(offset: { hash: $hash }) {
86
+ hash
87
+ raw
88
+ block { height timestamp }
89
+ unshieldedCreatedOutputs {
90
+ owner tokenType value intentHash outputIndex registeredForDustGeneration
91
+ }
92
+ unshieldedSpentOutputs {
93
+ owner tokenType value intentHash outputIndex registeredForDustGeneration
94
+ }
95
+ }
96
+ }`;
97
+ for (let i = 0; i < attempts; i++) {
98
+ const data = await gql(q, { hash });
99
+ if (data.transactions.length > 0)
100
+ return data.transactions[0];
101
+ await new Promise((r) => setTimeout(r, delayMs));
102
+ }
103
+ throw new Error(`transaction ${hash} not indexed after ${attempts} attempts`);
104
+ }
105
+ /** Byte size of a transaction as the node measured it, from the indexer's `raw` hex. */
106
+ export function transactionBytes(tx) {
107
+ const raw = tx.raw.startsWith('0x') ? tx.raw.slice(2) : tx.raw;
108
+ return raw.length / 2;
109
+ }
110
+ /**
111
+ * The node's dismiss-time allowance for a transaction of `bytes`, in milliseconds.
112
+ *
113
+ * `max(min_time_to_dismiss, time_to_dismiss_per_byte x size)` with ledger-9.1.0.0-rc.3's
114
+ * `INITIAL_LIMITS`: 15.000 ms and 0.002 ms/byte. A transaction is admissible only if this
115
+ * exceeds its dismiss cost, which is ~15.97 ms of fixed cryptographic constants -- hence the
116
+ * ~7,984-byte floor (docs/gate0-report.md).
117
+ */
118
+ export const allowanceMs = (bytes) => Math.max(15.0, 0.002 * bytes);
119
+ /** The floor a contract call must clear to be admitted at all, in bytes. */
120
+ export const ADMISSION_FLOOR_BYTES = 7984;
121
+ /**
122
+ * A contract's whole public history, oldest first.
123
+ *
124
+ * This is the ONLY thing `verify.ts` is given beyond the table's address: every join, every
125
+ * turn and the settlement are recovered from these actions and the contract states they point
126
+ * at. The indexer returns them newest-first, so they are reversed here.
127
+ */
128
+ export async function contractActions(address, limit = 1000) {
129
+ const data = await gql(`query ($address: HexEncoded!, $limit: Int!) {
130
+ contract(address: $address) {
131
+ actions(limit: $limit) {
132
+ __typename
133
+ ... on ContractCall { entryPoint transaction { hash block { height timestamp } } }
134
+ ... on ContractDeploy { transaction { hash block { height timestamp } } }
135
+ ... on ContractUpdate { transaction { hash block { height timestamp } } }
136
+ }
137
+ }
138
+ }`, { address, limit });
139
+ if (!data.contract)
140
+ throw new Error(`no contract at ${address}`);
141
+ return data.contract.actions
142
+ .map((a) => ({
143
+ kind: a.__typename,
144
+ entryPoint: a.entryPoint,
145
+ txHash: a.transaction.hash,
146
+ blockHeight: a.transaction.block.height,
147
+ blockTimestamp: Number(a.transaction.block.timestamp),
148
+ }))
149
+ .reverse();
150
+ }
151
+ /** Current chain tip, for sanity-checking that blocks are being produced. */
152
+ export async function tip() {
153
+ const data = await gql(`{ block { height timestamp } }`);
154
+ if (!data.block)
155
+ throw new Error('chain has no tip block');
156
+ return { height: data.block.height, timestamp: Number(data.block.timestamp) };
157
+ }
158
+ /**
159
+ * The `now` a state-advancing circuit should declare, in seconds since the epoch.
160
+ *
161
+ * Read off the CHAIN's latest block rather than from the local wall clock, and that choice is
162
+ * deliberate. `stampTime` traps the declared value in `(blockTime - 600, blockTime]`
163
+ * (table.compact, decision 5), so `now` must not exceed the block time of the block the
164
+ * transaction lands in. The tip's timestamp is by construction less than or equal to that of
165
+ * any later block, so it always satisfies the upper bound, and the transaction lands a few
166
+ * blocks later -- far inside the 600 s slack. A local clock a second fast would fail
167
+ * `blockTimeGte` instead, with an assertion message about time that says nothing about clocks.
168
+ */
169
+ export async function chainNowSecs() {
170
+ const { timestamp } = await tip();
171
+ return BigInt(Math.floor(timestamp / 1000));
172
+ }
173
+ //# sourceMappingURL=indexer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexer.js","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};