@aztec/ethereum 3.0.0-canary.a9708bd → 3.0.0-devnet.3

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.
Files changed (144) hide show
  1. package/dest/client.d.ts +1 -1
  2. package/dest/client.d.ts.map +1 -1
  3. package/dest/config.d.ts +11 -6
  4. package/dest/config.d.ts.map +1 -1
  5. package/dest/config.js +124 -64
  6. package/dest/contracts/empire_base.d.ts +1 -1
  7. package/dest/contracts/empire_base.d.ts.map +1 -1
  8. package/dest/contracts/empire_slashing_proposer.d.ts +2 -2
  9. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
  10. package/dest/contracts/empire_slashing_proposer.js +1 -1
  11. package/dest/contracts/fee_asset_handler.d.ts +3 -3
  12. package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
  13. package/dest/contracts/governance.js +7 -3
  14. package/dest/contracts/governance_proposer.d.ts +1 -2
  15. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  16. package/dest/contracts/governance_proposer.js +1 -2
  17. package/dest/contracts/multicall.d.ts +3 -5
  18. package/dest/contracts/multicall.d.ts.map +1 -1
  19. package/dest/contracts/multicall.js +6 -4
  20. package/dest/contracts/rollup.d.ts +39 -19
  21. package/dest/contracts/rollup.d.ts.map +1 -1
  22. package/dest/contracts/rollup.js +84 -88
  23. package/dest/contracts/slasher_contract.d.ts +10 -0
  24. package/dest/contracts/slasher_contract.d.ts.map +1 -1
  25. package/dest/contracts/slasher_contract.js +18 -0
  26. package/dest/contracts/tally_slashing_proposer.d.ts +22 -3
  27. package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
  28. package/dest/contracts/tally_slashing_proposer.js +55 -5
  29. package/dest/deploy_l1_contracts.d.ts +22 -7
  30. package/dest/deploy_l1_contracts.d.ts.map +1 -1
  31. package/dest/deploy_l1_contracts.js +555 -362
  32. package/dest/index.d.ts +1 -1
  33. package/dest/index.d.ts.map +1 -1
  34. package/dest/index.js +1 -1
  35. package/dest/l1_artifacts.d.ts +8729 -6014
  36. package/dest/l1_artifacts.d.ts.map +1 -1
  37. package/dest/l1_artifacts.js +10 -5
  38. package/dest/l1_contract_addresses.d.ts +5 -1
  39. package/dest/l1_contract_addresses.d.ts.map +1 -1
  40. package/dest/l1_contract_addresses.js +16 -26
  41. package/dest/l1_reader.d.ts +1 -1
  42. package/dest/l1_reader.d.ts.map +1 -1
  43. package/dest/l1_reader.js +8 -8
  44. package/dest/l1_tx_utils/config.d.ts +59 -0
  45. package/dest/l1_tx_utils/config.d.ts.map +1 -0
  46. package/dest/l1_tx_utils/config.js +73 -0
  47. package/dest/l1_tx_utils/constants.d.ts +6 -0
  48. package/dest/l1_tx_utils/constants.d.ts.map +1 -0
  49. package/dest/l1_tx_utils/constants.js +14 -0
  50. package/dest/l1_tx_utils/factory.d.ts +24 -0
  51. package/dest/l1_tx_utils/factory.d.ts.map +1 -0
  52. package/dest/l1_tx_utils/factory.js +12 -0
  53. package/dest/l1_tx_utils/index.d.ts +10 -0
  54. package/dest/l1_tx_utils/index.d.ts.map +1 -0
  55. package/dest/l1_tx_utils/index.js +10 -0
  56. package/dest/l1_tx_utils/interfaces.d.ts +76 -0
  57. package/dest/l1_tx_utils/interfaces.d.ts.map +1 -0
  58. package/dest/l1_tx_utils/interfaces.js +4 -0
  59. package/dest/l1_tx_utils/l1_tx_utils.d.ts +95 -0
  60. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
  61. package/dest/l1_tx_utils/l1_tx_utils.js +610 -0
  62. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +26 -0
  63. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -0
  64. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +26 -0
  65. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +81 -0
  66. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
  67. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +294 -0
  68. package/dest/l1_tx_utils/signer.d.ts +4 -0
  69. package/dest/l1_tx_utils/signer.d.ts.map +1 -0
  70. package/dest/l1_tx_utils/signer.js +16 -0
  71. package/dest/l1_tx_utils/types.d.ts +67 -0
  72. package/dest/l1_tx_utils/types.d.ts.map +1 -0
  73. package/dest/l1_tx_utils/types.js +26 -0
  74. package/dest/l1_tx_utils/utils.d.ts +4 -0
  75. package/dest/l1_tx_utils/utils.d.ts.map +1 -0
  76. package/dest/l1_tx_utils/utils.js +14 -0
  77. package/dest/publisher_manager.d.ts +7 -2
  78. package/dest/publisher_manager.d.ts.map +1 -1
  79. package/dest/publisher_manager.js +36 -8
  80. package/dest/queries.d.ts.map +1 -1
  81. package/dest/queries.js +11 -12
  82. package/dest/test/chain_monitor.d.ts +11 -0
  83. package/dest/test/chain_monitor.d.ts.map +1 -1
  84. package/dest/test/chain_monitor.js +81 -12
  85. package/dest/test/delayed_tx_utils.d.ts +2 -2
  86. package/dest/test/delayed_tx_utils.d.ts.map +1 -1
  87. package/dest/test/delayed_tx_utils.js +2 -2
  88. package/dest/test/eth_cheat_codes.d.ts +32 -6
  89. package/dest/test/eth_cheat_codes.d.ts.map +1 -1
  90. package/dest/test/eth_cheat_codes.js +115 -28
  91. package/dest/test/rollup_cheat_codes.d.ts +11 -9
  92. package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
  93. package/dest/test/rollup_cheat_codes.js +38 -6
  94. package/dest/test/upgrade_utils.d.ts.map +1 -1
  95. package/dest/test/upgrade_utils.js +3 -2
  96. package/dest/utils.d.ts.map +1 -1
  97. package/dest/utils.js +10 -161
  98. package/dest/zkPassportVerifierAddress.js +1 -1
  99. package/package.json +7 -7
  100. package/src/client.ts +1 -1
  101. package/src/config.ts +136 -68
  102. package/src/contracts/empire_base.ts +1 -1
  103. package/src/contracts/empire_slashing_proposer.ts +7 -3
  104. package/src/contracts/fee_asset_handler.ts +1 -1
  105. package/src/contracts/governance.ts +3 -3
  106. package/src/contracts/governance_proposer.ts +3 -4
  107. package/src/contracts/multicall.ts +12 -10
  108. package/src/contracts/rollup.ts +104 -106
  109. package/src/contracts/slasher_contract.ts +22 -0
  110. package/src/contracts/tally_slashing_proposer.ts +54 -6
  111. package/src/deploy_l1_contracts.ts +570 -328
  112. package/src/index.ts +1 -1
  113. package/src/l1_artifacts.ts +14 -6
  114. package/src/l1_contract_addresses.ts +17 -26
  115. package/src/l1_reader.ts +9 -9
  116. package/src/l1_tx_utils/README.md +177 -0
  117. package/src/l1_tx_utils/config.ts +140 -0
  118. package/src/l1_tx_utils/constants.ts +18 -0
  119. package/src/l1_tx_utils/factory.ts +64 -0
  120. package/src/l1_tx_utils/index.ts +12 -0
  121. package/src/l1_tx_utils/interfaces.ts +86 -0
  122. package/src/l1_tx_utils/l1_tx_utils.ts +718 -0
  123. package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +77 -0
  124. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +372 -0
  125. package/src/l1_tx_utils/signer.ts +28 -0
  126. package/src/l1_tx_utils/types.ts +85 -0
  127. package/src/l1_tx_utils/utils.ts +16 -0
  128. package/src/publisher_manager.ts +51 -9
  129. package/src/queries.ts +13 -8
  130. package/src/test/chain_monitor.ts +89 -9
  131. package/src/test/delayed_tx_utils.ts +2 -2
  132. package/src/test/eth_cheat_codes.ts +142 -29
  133. package/src/test/rollup_cheat_codes.ts +54 -14
  134. package/src/test/upgrade_utils.ts +3 -2
  135. package/src/utils.ts +13 -185
  136. package/src/zkPassportVerifierAddress.ts +1 -1
  137. package/dest/l1_tx_utils.d.ts +0 -250
  138. package/dest/l1_tx_utils.d.ts.map +0 -1
  139. package/dest/l1_tx_utils.js +0 -826
  140. package/dest/l1_tx_utils_with_blobs.d.ts +0 -19
  141. package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
  142. package/dest/l1_tx_utils_with_blobs.js +0 -85
  143. package/src/l1_tx_utils.ts +0 -1105
  144. package/src/l1_tx_utils_with_blobs.ts +0 -144
@@ -0,0 +1,81 @@
1
+ import { type Logger } from '@aztec/foundation/log';
2
+ import { DateProvider } from '@aztec/foundation/timer';
3
+ import { type Abi, type Account, type BlockOverrides, type Hex, type StateOverride } from 'viem';
4
+ import type { ViemClient } from '../types.js';
5
+ import { type L1TxUtilsConfig } from './config.js';
6
+ import type { GasPrice, L1BlobInputs, L1TxRequest, TransactionStats } from './types.js';
7
+ export declare class ReadOnlyL1TxUtils {
8
+ client: ViemClient;
9
+ protected logger: Logger;
10
+ readonly dateProvider: DateProvider;
11
+ protected debugMaxGasLimit: boolean;
12
+ config: Required<L1TxUtilsConfig>;
13
+ protected interrupted: boolean;
14
+ constructor(client: ViemClient, logger: Logger | undefined, dateProvider: DateProvider, config?: Partial<L1TxUtilsConfig>, debugMaxGasLimit?: boolean);
15
+ interrupt(): void;
16
+ restart(): void;
17
+ getBlock(): Promise<{
18
+ number: bigint;
19
+ hash: `0x${string}`;
20
+ nonce: `0x${string}`;
21
+ logsBloom: `0x${string}`;
22
+ baseFeePerGas: bigint | null;
23
+ blobGasUsed: bigint;
24
+ difficulty: bigint;
25
+ excessBlobGas: bigint;
26
+ extraData: Hex;
27
+ gasLimit: bigint;
28
+ gasUsed: bigint;
29
+ miner: import("viem").Address;
30
+ mixHash: import("viem").Hash;
31
+ parentBeaconBlockRoot?: `0x${string}` | undefined;
32
+ parentHash: import("viem").Hash;
33
+ receiptsRoot: Hex;
34
+ sealFields: Hex[];
35
+ sha3Uncles: import("viem").Hash;
36
+ size: bigint;
37
+ stateRoot: import("viem").Hash;
38
+ timestamp: bigint;
39
+ totalDifficulty: bigint | null;
40
+ transactionsRoot: import("viem").Hash;
41
+ uncles: import("viem").Hash[];
42
+ withdrawals?: import("viem").Withdrawal[] | undefined | undefined;
43
+ withdrawalsRoot?: `0x${string}` | undefined;
44
+ transactions: `0x${string}`[];
45
+ }>;
46
+ getBlockNumber(): Promise<bigint>;
47
+ /**
48
+ * Gets the current gas price with bounds checking
49
+ */
50
+ getGasPrice(gasConfigOverrides?: L1TxUtilsConfig, isBlobTx?: boolean, attempt?: number, previousGasPrice?: typeof attempt extends 0 ? never : GasPrice): Promise<GasPrice>;
51
+ /**
52
+ * Estimates gas and adds buffer
53
+ */
54
+ estimateGas(account: Account | Hex, request: L1TxRequest, _gasConfig?: L1TxUtilsConfig, _blobInputs?: L1BlobInputs): Promise<bigint>;
55
+ getTransactionStats(txHash: string): Promise<TransactionStats | undefined>;
56
+ tryGetErrorFromRevertedTx(data: Hex, args: {
57
+ args: readonly any[];
58
+ functionName: string;
59
+ abi: Abi;
60
+ address: Hex;
61
+ }, blobInputs: (L1BlobInputs & {
62
+ maxFeePerBlobGas: bigint;
63
+ }) | undefined, stateOverride?: StateOverride): Promise<string | undefined>;
64
+ simulate(request: L1TxRequest & {
65
+ gas?: bigint;
66
+ from?: Hex;
67
+ }, blockOverrides?: BlockOverrides<bigint, number>, stateOverrides?: StateOverride, abi?: Abi, _gasConfig?: L1TxUtilsConfig & {
68
+ fallbackGasEstimate?: bigint;
69
+ }): Promise<{
70
+ gasUsed: bigint;
71
+ result: `0x${string}`;
72
+ }>;
73
+ protected _simulate(call: any, blockOverrides: BlockOverrides<bigint, number> | undefined, stateOverrides: StateOverride | undefined, gasConfig: L1TxUtilsConfig & {
74
+ fallbackGasEstimate?: bigint;
75
+ }, abi: Abi): Promise<{
76
+ gasUsed: bigint;
77
+ result: `0x${string}`;
78
+ }>;
79
+ bumpGasLimit(gasLimit: bigint, _gasConfig?: L1TxUtilsConfig): bigint;
80
+ }
81
+ //# sourceMappingURL=readonly_l1_tx_utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readonly_l1_tx_utils.d.ts","sourceRoot":"","sources":["../../src/l1_tx_utils/readonly_l1_tx_utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,294 @@
1
+ import { getKeys, merge, pick, times } from '@aztec/foundation/collection';
2
+ import { createLogger } from '@aztec/foundation/log';
3
+ import { makeBackoff, retry } from '@aztec/foundation/retry';
4
+ import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
5
+ import pickBy from 'lodash.pickby';
6
+ import { MethodNotFoundRpcError, MethodNotSupportedRpcError, decodeErrorResult, formatGwei, getContractError, hexToBytes } from 'viem';
7
+ import { defaultL1TxUtilsConfig, l1TxUtilsConfigMappings } from './config.js';
8
+ import { BLOCK_TIME_MS, LARGE_GAS_LIMIT, MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE, MIN_REPLACEMENT_BUMP_PERCENTAGE, WEI_CONST } from './constants.js';
9
+ import { getCalldataGasUsage, tryGetCustomErrorNameContractFunction } from './utils.js';
10
+ export class ReadOnlyL1TxUtils {
11
+ client;
12
+ logger;
13
+ dateProvider;
14
+ debugMaxGasLimit;
15
+ config;
16
+ interrupted;
17
+ constructor(client, logger = createLogger('ethereum:readonly-l1-utils'), dateProvider, config, debugMaxGasLimit = false){
18
+ this.client = client;
19
+ this.logger = logger;
20
+ this.dateProvider = dateProvider;
21
+ this.debugMaxGasLimit = debugMaxGasLimit;
22
+ this.interrupted = false;
23
+ this.config = merge(defaultL1TxUtilsConfig, pick(config || {}, ...getKeys(l1TxUtilsConfigMappings)));
24
+ }
25
+ interrupt() {
26
+ this.interrupted = true;
27
+ }
28
+ restart() {
29
+ this.interrupted = false;
30
+ }
31
+ getBlock() {
32
+ return this.client.getBlock();
33
+ }
34
+ getBlockNumber() {
35
+ return this.client.getBlockNumber();
36
+ }
37
+ /**
38
+ * Gets the current gas price with bounds checking
39
+ */ async getGasPrice(gasConfigOverrides, isBlobTx = false, attempt = 0, previousGasPrice) {
40
+ const gasConfig = merge(this.config, gasConfigOverrides);
41
+ const block = await this.client.getBlock({
42
+ blockTag: 'latest'
43
+ });
44
+ const baseFee = block.baseFeePerGas ?? 0n;
45
+ // Get blob base fee if available
46
+ let blobBaseFee = 0n;
47
+ if (isBlobTx) {
48
+ try {
49
+ blobBaseFee = await retry(()=>this.client.getBlobBaseFee(), 'Getting L1 blob base fee', makeBackoff(times(2, ()=>1)), this.logger, true);
50
+ } catch {
51
+ this.logger?.warn('Failed to get L1 blob base fee', attempt);
52
+ }
53
+ }
54
+ let priorityFee;
55
+ if (gasConfig.fixedPriorityFeePerGas) {
56
+ this.logger?.debug('Using fixed priority fee per L1 gas', {
57
+ fixedPriorityFeePerGas: gasConfig.fixedPriorityFeePerGas
58
+ });
59
+ // try to maintain precision up to 1000000 wei
60
+ priorityFee = BigInt(gasConfig.fixedPriorityFeePerGas * 1_000_000) * (WEI_CONST / 1_000_000n);
61
+ } else {
62
+ // Get initial priority fee from the network
63
+ priorityFee = await this.client.estimateMaxPriorityFeePerGas();
64
+ }
65
+ let maxFeePerGas = baseFee;
66
+ let maxFeePerBlobGas = blobBaseFee;
67
+ // Bump base fee so it's valid for next blocks if it stalls
68
+ const numBlocks = Math.ceil(gasConfig.stallTimeMs / BLOCK_TIME_MS);
69
+ for(let i = 0; i < numBlocks; i++){
70
+ // each block can go up 12.5% from previous baseFee
71
+ maxFeePerGas = maxFeePerGas * (1_000n + 125n) / 1_000n;
72
+ // same for blob gas fee
73
+ maxFeePerBlobGas = maxFeePerBlobGas * (1_000n + 125n) / 1_000n;
74
+ }
75
+ if (attempt > 0) {
76
+ const configBump = gasConfig.priorityFeeRetryBumpPercentage ?? defaultL1TxUtilsConfig.priorityFeeRetryBumpPercentage;
77
+ // if this is a blob tx, we have to use the blob bump percentage
78
+ const minBumpPercentage = isBlobTx ? MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE : MIN_REPLACEMENT_BUMP_PERCENTAGE;
79
+ const bumpPercentage = configBump > minBumpPercentage ? configBump : minBumpPercentage;
80
+ // Calculate minimum required fees based on previous attempt
81
+ // multiply by 100 & divide by 100 to maintain some precision
82
+ const minPriorityFee = previousGasPrice.maxPriorityFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
83
+ const minMaxFee = previousGasPrice.maxFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
84
+ // Add priority fee to maxFeePerGas
85
+ maxFeePerGas += priorityFee;
86
+ // Use maximum between current network values and minimum required values
87
+ priorityFee = priorityFee > minPriorityFee ? priorityFee : minPriorityFee;
88
+ maxFeePerGas = maxFeePerGas > minMaxFee ? maxFeePerGas : minMaxFee;
89
+ } else {
90
+ // first attempt, just bump priority fee, unless it's a fixed config
91
+ // multiply by 100 & divide by 100 to maintain some precision
92
+ if (!gasConfig.fixedPriorityFeePerGas) {
93
+ priorityFee = priorityFee * (100_00n + BigInt((gasConfig.priorityFeeBumpPercentage || 0) * 1_00)) / 100_00n;
94
+ }
95
+ maxFeePerGas += priorityFee;
96
+ }
97
+ // Ensure we don't exceed maxGwei
98
+ const maxGweiInWei = gasConfig.maxGwei * WEI_CONST;
99
+ maxFeePerGas = maxFeePerGas > maxGweiInWei ? maxGweiInWei : maxFeePerGas;
100
+ // Ensure we don't exceed maxBlobGwei
101
+ if (maxFeePerBlobGas) {
102
+ const maxBlobGweiInWei = gasConfig.maxBlobGwei * WEI_CONST;
103
+ maxFeePerBlobGas = maxFeePerBlobGas > maxBlobGweiInWei ? maxBlobGweiInWei : maxFeePerBlobGas;
104
+ }
105
+ // Ensure priority fee doesn't exceed max fee
106
+ const maxPriorityFeePerGas = priorityFee > maxFeePerGas ? maxFeePerGas : priorityFee;
107
+ if (attempt > 0 && previousGasPrice?.maxFeePerBlobGas) {
108
+ const bumpPercentage = gasConfig.priorityFeeRetryBumpPercentage > MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE ? gasConfig.priorityFeeRetryBumpPercentage : MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE;
109
+ // calculate min blob fee based on previous attempt
110
+ const minBlobFee = previousGasPrice.maxFeePerBlobGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
111
+ // use max between current network values and min required values
112
+ maxFeePerBlobGas = maxFeePerBlobGas > minBlobFee ? maxFeePerBlobGas : minBlobFee;
113
+ }
114
+ this.logger?.trace(`Computed L1 gas price max fee ${formatGwei(maxFeePerGas)} and max priority fee ${formatGwei(maxPriorityFeePerGas)}`, {
115
+ attempt,
116
+ baseFee: formatGwei(baseFee),
117
+ maxFeePerGas: formatGwei(maxFeePerGas),
118
+ maxPriorityFeePerGas: formatGwei(maxPriorityFeePerGas),
119
+ blobBaseFee: formatGwei(blobBaseFee),
120
+ maxFeePerBlobGas: formatGwei(maxFeePerBlobGas)
121
+ });
122
+ return {
123
+ maxFeePerGas,
124
+ maxPriorityFeePerGas,
125
+ ...maxFeePerBlobGas && {
126
+ maxFeePerBlobGas: maxFeePerBlobGas
127
+ }
128
+ };
129
+ }
130
+ /**
131
+ * Estimates gas and adds buffer
132
+ */ async estimateGas(account, request, _gasConfig, _blobInputs) {
133
+ const gasConfig = {
134
+ ...this.config,
135
+ ..._gasConfig
136
+ };
137
+ let initialEstimate = 0n;
138
+ if (_blobInputs) {
139
+ // @note requests with blobs also require maxFeePerBlobGas to be set
140
+ const gasPrice = await this.getGasPrice(gasConfig, true, 0);
141
+ initialEstimate = await this.client.estimateGas({
142
+ account,
143
+ ...request,
144
+ ..._blobInputs,
145
+ maxFeePerBlobGas: gasPrice.maxFeePerBlobGas,
146
+ gas: LARGE_GAS_LIMIT
147
+ });
148
+ this.logger?.trace(`Estimated gas for blob tx: ${initialEstimate}`);
149
+ } else {
150
+ initialEstimate = await this.client.estimateGas({
151
+ account,
152
+ ...request,
153
+ gas: LARGE_GAS_LIMIT
154
+ });
155
+ this.logger?.trace(`Estimated gas for non-blob tx: ${initialEstimate}`);
156
+ }
157
+ // Add buffer based on either fixed amount or percentage
158
+ const withBuffer = this.bumpGasLimit(initialEstimate, gasConfig);
159
+ return withBuffer;
160
+ }
161
+ async getTransactionStats(txHash) {
162
+ const tx = await this.client.getTransaction({
163
+ hash: txHash
164
+ });
165
+ if (!tx) {
166
+ return undefined;
167
+ }
168
+ const calldata = hexToBytes(tx.input);
169
+ return {
170
+ sender: tx.from.toString(),
171
+ transactionHash: tx.hash,
172
+ calldataSize: calldata.length,
173
+ calldataGas: getCalldataGasUsage(calldata)
174
+ };
175
+ }
176
+ async tryGetErrorFromRevertedTx(data, args, blobInputs, stateOverride = []) {
177
+ try {
178
+ await this.client.simulateContract({
179
+ ...args,
180
+ account: this.client.account,
181
+ stateOverride
182
+ });
183
+ this.logger?.trace('Simulated blob tx', {
184
+ blobInputs
185
+ });
186
+ // If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors.
187
+ // Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
188
+ // See: https://github.com/wevm/viem/issues/2075
189
+ // This throws a EstimateGasExecutionError with the custom error information:
190
+ const request = blobInputs ? {
191
+ account: this.client.account,
192
+ to: args.address,
193
+ data,
194
+ blobs: blobInputs.blobs,
195
+ kzg: blobInputs.kzg,
196
+ maxFeePerBlobGas: blobInputs.maxFeePerBlobGas
197
+ } : {
198
+ account: this.client.account,
199
+ to: args.address,
200
+ data
201
+ };
202
+ this.logger?.trace('Preparing tx', {
203
+ request
204
+ });
205
+ await this.client.prepareTransactionRequest(request);
206
+ this.logger?.trace('Prepared tx');
207
+ return undefined;
208
+ } catch (simulationErr) {
209
+ // If we don't have a ContractFunctionExecutionError, we have a blob related error => use getContractError to get the error msg.
210
+ const contractErr = simulationErr.name === 'ContractFunctionExecutionError' ? simulationErr : getContractError(simulationErr, {
211
+ args: [],
212
+ abi: args.abi,
213
+ functionName: args.functionName,
214
+ address: args.address
215
+ });
216
+ if (contractErr.name === 'ContractFunctionExecutionError') {
217
+ const execErr = contractErr;
218
+ return tryGetCustomErrorNameContractFunction(execErr);
219
+ }
220
+ this.logger?.error(`Error getting error from simulation`, simulationErr);
221
+ }
222
+ }
223
+ async simulate(request, blockOverrides = {}, stateOverrides = [], abi = RollupAbi, _gasConfig) {
224
+ const gasConfig = {
225
+ ...this.config,
226
+ ..._gasConfig
227
+ };
228
+ const call = {
229
+ to: request.to,
230
+ data: request.data,
231
+ ...request.from && {
232
+ from: request.from
233
+ }
234
+ };
235
+ return await this._simulate(call, blockOverrides, stateOverrides, gasConfig, abi);
236
+ }
237
+ async _simulate(call, blockOverrides = {}, stateOverrides = [], gasConfig, abi) {
238
+ try {
239
+ const result = await this.client.simulateBlocks({
240
+ validation: false,
241
+ blocks: [
242
+ {
243
+ blockOverrides,
244
+ stateOverrides,
245
+ calls: [
246
+ call
247
+ ]
248
+ }
249
+ ]
250
+ });
251
+ if (result[0].calls[0].status === 'failure') {
252
+ this.logger?.error('L1 transaction simulation failed', result[0].calls[0].error);
253
+ const decodedError = decodeErrorResult({
254
+ abi,
255
+ data: result[0].calls[0].data
256
+ });
257
+ throw new Error(`L1 transaction simulation failed with error ${decodedError.errorName}(${decodedError.args?.join(',')})`);
258
+ }
259
+ this.logger?.debug(`L1 transaction simulation succeeded`, {
260
+ ...result[0].calls[0]
261
+ });
262
+ return {
263
+ gasUsed: result[0].gasUsed,
264
+ result: result[0].calls[0].data
265
+ };
266
+ } catch (err) {
267
+ if (err instanceof MethodNotFoundRpcError || err instanceof MethodNotSupportedRpcError) {
268
+ if (gasConfig.fallbackGasEstimate) {
269
+ this.logger?.warn(`Node does not support eth_simulateV1 API. Using fallback gas estimate: ${gasConfig.fallbackGasEstimate}`);
270
+ return {
271
+ gasUsed: gasConfig.fallbackGasEstimate,
272
+ result: '0x'
273
+ };
274
+ }
275
+ this.logger?.error('Node does not support eth_simulateV1 API');
276
+ }
277
+ throw err;
278
+ }
279
+ }
280
+ bumpGasLimit(gasLimit, _gasConfig) {
281
+ const gasConfig = {
282
+ ...this.config,
283
+ ..._gasConfig
284
+ };
285
+ const bumpedGasLimit = gasLimit + gasLimit * BigInt((gasConfig?.gasLimitBufferPercentage || 0) * 1_00) / 100_00n;
286
+ const cleanGasConfig = pickBy(gasConfig, (_, key)=>key in l1TxUtilsConfigMappings);
287
+ this.logger?.trace(`Bumping gas limit from ${gasLimit} to ${bumpedGasLimit}`, {
288
+ gasLimit,
289
+ gasConfig: cleanGasConfig,
290
+ bumpedGasLimit
291
+ });
292
+ return bumpedGasLimit;
293
+ }
294
+ }
@@ -0,0 +1,4 @@
1
+ import { type WalletClient } from 'viem';
2
+ import type { SigningCallback } from './types.js';
3
+ export declare function createViemSigner(client: WalletClient): SigningCallback;
4
+ //# sourceMappingURL=signer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../../src/l1_tx_utils/signer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgC,KAAK,YAAY,EAAoB,MAAM,MAAM,CAAC;AAEzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,mBAoBpD"}
@@ -0,0 +1,16 @@
1
+ import { parseTransaction } from 'viem';
2
+ export function createViemSigner(client) {
3
+ const signer = async (tx, _address)=>{
4
+ const signedTx = await client.signTransaction(tx);
5
+ const parsed = parseTransaction(signedTx);
6
+ if (!parsed.r || !parsed.s || parsed.yParity !== 0 && parsed.yParity !== 1) {
7
+ throw new Error('Failed to extract signature from viem signed transaction');
8
+ }
9
+ return {
10
+ r: parsed.r,
11
+ s: parsed.s,
12
+ yParity: parsed.yParity
13
+ };
14
+ };
15
+ return signer;
16
+ }
@@ -0,0 +1,67 @@
1
+ import type { BlobKzgInstance } from '@aztec/blob-lib/types';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import type { ViemTransactionSignature } from '@aztec/foundation/eth-signature';
4
+ import type { Abi, Address, Hex, TransactionReceipt, TransactionSerializable } from 'viem';
5
+ import type { L1TxUtilsConfig } from './config.js';
6
+ export interface L1TxRequest {
7
+ to: Address | null;
8
+ data?: Hex;
9
+ value?: bigint;
10
+ abi?: Abi;
11
+ }
12
+ export type L1TxConfig = Partial<L1TxUtilsConfig> & {
13
+ gasLimit?: bigint;
14
+ txTimeoutAt?: Date;
15
+ };
16
+ export interface L1BlobInputs {
17
+ blobs: Uint8Array[];
18
+ kzg: BlobKzgInstance;
19
+ maxFeePerBlobGas?: bigint;
20
+ }
21
+ export interface GasPrice {
22
+ maxFeePerGas: bigint;
23
+ maxPriorityFeePerGas: bigint;
24
+ maxFeePerBlobGas?: bigint;
25
+ }
26
+ export type TransactionStats = {
27
+ /** Address of the sender. */
28
+ sender: string;
29
+ /** Hash of the transaction. */
30
+ transactionHash: string;
31
+ /** Size in bytes of the tx calldata */
32
+ calldataSize: number;
33
+ /** Gas required to pay for the calldata inclusion (depends on size and number of zeros) */
34
+ calldataGas: number;
35
+ };
36
+ export declare enum TxUtilsState {
37
+ IDLE = 0,
38
+ SENT = 1,
39
+ SPEED_UP = 2,
40
+ CANCELLED = 3,
41
+ NOT_MINED = 4,
42
+ MINED = 5
43
+ }
44
+ export declare const TerminalTxUtilsState: TxUtilsState[];
45
+ export type L1TxState = {
46
+ id: number;
47
+ txHashes: Hex[];
48
+ cancelTxHashes: Hex[];
49
+ gasLimit: bigint;
50
+ gasPrice: GasPrice;
51
+ txConfigOverrides: L1TxConfig;
52
+ request: L1TxRequest;
53
+ status: TxUtilsState;
54
+ nonce: number;
55
+ sentAtL1Ts: Date;
56
+ lastSentAtL1Ts: Date;
57
+ receipt?: TransactionReceipt;
58
+ blobInputs: L1BlobInputs | undefined;
59
+ };
60
+ export type SigningCallback = (transaction: TransactionSerializable, signingAddress: EthAddress) => Promise<ViemTransactionSignature>;
61
+ export declare class UnknownMinedTxError extends Error {
62
+ constructor(nonce: number, account: string);
63
+ }
64
+ export declare class DroppedTransactionError extends Error {
65
+ constructor(nonce: number, account: string);
66
+ }
67
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/l1_tx_utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,MAAM,CAAC;AAE3F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAE9F,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,GAAG,EAAE,eAAe,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,oBAAY,YAAY;IACtB,IAAI,IAAA;IACJ,IAAI,IAAA;IACJ,QAAQ,IAAA;IACR,SAAS,IAAA;IACT,SAAS,IAAA;IACT,KAAK,IAAA;CACN;AAED,eAAO,MAAM,oBAAoB,gBAAkE,CAAC;AAEpG,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,cAAc,EAAE,GAAG,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,EAAE,UAAU,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,IAAI,CAAC;IACjB,cAAc,EAAE,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,YAAY,GAAG,SAAS,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAC5B,WAAW,EAAE,uBAAuB,EACpC,cAAc,EAAE,UAAU,KACvB,OAAO,CAAC,wBAAwB,CAAC,CAAC;AAEvC,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAI3C;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAI3C"}
@@ -0,0 +1,26 @@
1
+ export var TxUtilsState = /*#__PURE__*/ function(TxUtilsState) {
2
+ TxUtilsState[TxUtilsState["IDLE"] = 0] = "IDLE";
3
+ TxUtilsState[TxUtilsState["SENT"] = 1] = "SENT";
4
+ TxUtilsState[TxUtilsState["SPEED_UP"] = 2] = "SPEED_UP";
5
+ TxUtilsState[TxUtilsState["CANCELLED"] = 3] = "CANCELLED";
6
+ TxUtilsState[TxUtilsState["NOT_MINED"] = 4] = "NOT_MINED";
7
+ TxUtilsState[TxUtilsState["MINED"] = 5] = "MINED";
8
+ return TxUtilsState;
9
+ }({});
10
+ export const TerminalTxUtilsState = [
11
+ 0,
12
+ 5,
13
+ 4
14
+ ];
15
+ export class UnknownMinedTxError extends Error {
16
+ constructor(nonce, account){
17
+ super(`Nonce ${nonce} from account ${account} is MINED but not by one of our expected transactions`);
18
+ this.name = 'UnknownMinedTxError';
19
+ }
20
+ }
21
+ export class DroppedTransactionError extends Error {
22
+ constructor(nonce, account){
23
+ super(`Transaction with nonce ${nonce} from account ${account} was dropped from the mempool`);
24
+ this.name = 'DroppedTransactionError';
25
+ }
26
+ }
@@ -0,0 +1,4 @@
1
+ import type { ContractFunctionExecutionError } from 'viem';
2
+ export declare function tryGetCustomErrorNameContractFunction(err: ContractFunctionExecutionError): string;
3
+ export declare function getCalldataGasUsage(data: Uint8Array): number;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/l1_tx_utils/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,MAAM,CAAC;AAE3D,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,8BAA8B,UAExF;AAOD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,UAEnD"}
@@ -0,0 +1,14 @@
1
+ import { compactArray } from '@aztec/foundation/collection';
2
+ export function tryGetCustomErrorNameContractFunction(err) {
3
+ return compactArray([
4
+ err.shortMessage,
5
+ ...(err.metaMessages ?? []).slice(0, 2).map((s)=>s.trim())
6
+ ]).join(' ');
7
+ }
8
+ /*
9
+ * Returns cost of calldata usage in Ethereum.
10
+ * @param data - Calldata.
11
+ * @returns 4 for each zero byte, 16 for each nonzero.
12
+ */ export function getCalldataGasUsage(data) {
13
+ return data.filter((byte)=>byte === 0).length * 4 + data.filter((byte)=>byte !== 0).length * 16;
14
+ }
@@ -1,9 +1,14 @@
1
- import { L1TxUtils } from './l1_tx_utils.js';
1
+ import { L1TxUtils } from './l1_tx_utils/index.js';
2
2
  export type PublisherFilter<UtilsType extends L1TxUtils> = (utils: UtilsType) => boolean;
3
3
  export declare class PublisherManager<UtilsType extends L1TxUtils = L1TxUtils> {
4
4
  private publishers;
5
5
  private log;
6
- constructor(publishers: UtilsType[]);
6
+ private config;
7
+ constructor(publishers: UtilsType[], config: {
8
+ publisherAllowInvalidStates?: boolean;
9
+ });
10
+ /** Loads the state of all publishers and resumes monitoring any pending txs */
11
+ loadState(): Promise<void>;
7
12
  getAvailablePublisher(filter?: PublisherFilter<UtilsType>): Promise<UtilsType>;
8
13
  interrupt(): void;
9
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"publisher_manager.d.ts","sourceRoot":"","sources":["../src/publisher_manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAgB,MAAM,kBAAkB,CAAC;AAK3D,MAAM,MAAM,eAAe,CAAC,SAAS,SAAS,SAAS,IAAI,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;AAEzF,qBAAa,gBAAgB,CAAC,SAAS,SAAS,SAAS,GAAG,SAAS;IAGvD,OAAO,CAAC,UAAU;IAF9B,OAAO,CAAC,GAAG,CAAoC;gBAE3B,UAAU,EAAE,SAAS,EAAE;IAW9B,qBAAqB,CAAC,MAAM,GAAE,eAAe,CAAC,SAAS,CAAc,GAAG,OAAO,CAAC,SAAS,CAAC;IAqChG,SAAS;CAGjB"}
1
+ {"version":3,"file":"publisher_manager.d.ts","sourceRoot":"","sources":["../src/publisher_manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAgB,MAAM,wBAAwB,CAAC;AAwBjE,MAAM,MAAM,eAAe,CAAC,SAAS,SAAS,SAAS,IAAI,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;AAEzF,qBAAa,gBAAgB,CAAC,SAAS,SAAS,SAAS,GAAG,SAAS;IAKjE,OAAO,CAAC,UAAU;IAJpB,OAAO,CAAC,GAAG,CAAqC;IAChD,OAAO,CAAC,MAAM,CAA4C;gBAGhD,UAAU,EAAE,SAAS,EAAE,EAC/B,MAAM,EAAE;QAAE,2BAA2B,CAAC,EAAE,OAAO,CAAA;KAAE;IAOnD,+EAA+E;IAClE,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAU1B,qBAAqB,CAAC,MAAM,GAAE,eAAe,CAAC,SAAS,CAAc,GAAG,OAAO,CAAC,SAAS,CAAC;IAiDhG,SAAS;CAGjB"}
@@ -1,33 +1,61 @@
1
+ import { pick } from '@aztec/foundation/collection';
1
2
  import { createLogger } from '@aztec/foundation/log';
2
- import { TxUtilsState } from './l1_tx_utils.js';
3
+ import { TxUtilsState } from './l1_tx_utils/index.js';
4
+ // Defines the order in which we prioritise publishers based on their state (first is better)
3
5
  const sortOrder = [
6
+ // Always prefer sending from idle publishers
4
7
  TxUtilsState.IDLE,
5
- TxUtilsState.MINED
8
+ // Then from publishers that have sent a tx and it got mined
9
+ TxUtilsState.MINED,
10
+ // Then from publishers that have sent a tx but it's in-flight
11
+ TxUtilsState.SPEED_UP,
12
+ TxUtilsState.SENT,
13
+ // We leave cancelled and not-mined states for last, since these represent failures to mines and could be problematic
14
+ TxUtilsState.CANCELLED,
15
+ TxUtilsState.NOT_MINED
6
16
  ];
7
- const invalidStates = [
17
+ // Which states represent a busy publisher that we should avoid if possible
18
+ const busyStates = [
8
19
  TxUtilsState.SENT,
9
20
  TxUtilsState.SPEED_UP,
10
21
  TxUtilsState.CANCELLED,
11
22
  TxUtilsState.NOT_MINED
12
- ]; // Cancelled and not mined are states that can be handled by a later iteration
23
+ ];
13
24
  export class PublisherManager {
14
25
  publishers;
15
26
  log;
16
- constructor(publishers){
27
+ config;
28
+ constructor(publishers, config){
17
29
  this.publishers = publishers;
18
- this.log = createLogger('PublisherManager');
30
+ this.log = createLogger('publisher:manager');
19
31
  this.log.info(`PublisherManager initialized with ${publishers.length} publishers.`);
20
32
  this.publishers = publishers;
33
+ this.config = pick(config, 'publisherAllowInvalidStates');
34
+ }
35
+ /** Loads the state of all publishers and resumes monitoring any pending txs */ async loadState() {
36
+ await Promise.all(this.publishers.map((pub)=>pub.loadStateAndResumeMonitoring()));
21
37
  }
22
38
  // Finds and prioritises available publishers based on
23
39
  // 1. Validity as per the provided filter function
24
40
  // 2. Validity based on the state the publisher is in
25
- // 3. Priority based on state as defined bu sortOrder
41
+ // 3. Priority based on state as defined by sortOrder
26
42
  // 4. Then priority based on highest balance
27
43
  // 5. Then priority based on least recently used
28
44
  async getAvailablePublisher(filter = ()=>true) {
45
+ this.log.debug(`Getting available publisher`, {
46
+ publishers: this.publishers.map((p)=>({
47
+ address: p.getSenderAddress(),
48
+ state: p.state,
49
+ lastMined: p.lastMinedAtBlockNumber
50
+ }))
51
+ });
29
52
  // Extract the valid publishers
30
- const validPublishers = this.publishers.filter((pub)=>!invalidStates.includes(pub.state) && filter(pub));
53
+ let validPublishers = this.publishers.filter((pub)=>!busyStates.includes(pub.state) && filter(pub));
54
+ // If none found but we allow invalid (busy) states, try again including them
55
+ if (validPublishers.length === 0 && this.config.publisherAllowInvalidStates) {
56
+ this.log.warn(`No valid publishers found. Trying again including invalid states.`);
57
+ validPublishers = this.publishers.filter((pub)=>filter(pub));
58
+ }
31
59
  // Error if none found
32
60
  if (validPublishers.length === 0) {
33
61
  throw new Error(`Failed to find an available publisher.`);
@@ -1 +1 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAK3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,qDAAqD;AACrD,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE;IAAE,iBAAiB,EAAE,UAAU,CAAC;IAAC,aAAa,CAAC,EAAE,UAAU,CAAA;CAAE,GACvE,OAAO,CACR,IAAI,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,GAAG;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,KAAK,MAAM,EAAE,CAAC;CACvC,CACF,CAqFA"}
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,qDAAqD;AACrD,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE;IAAE,iBAAiB,EAAE,UAAU,CAAC;IAAC,aAAa,CAAC,EAAE,UAAU,CAAA;CAAE,GACvE,OAAO,CACR,IAAI,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,GAAG;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,KAAK,MAAM,EAAE,CAAC;CACvC,CACF,CA6FA"}