@aztec/ethereum 0.0.1-commit.0c875d939 → 0.0.1-commit.0ec55a70b
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/dest/client.d.ts +16 -2
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +27 -7
- package/dest/config.d.ts +8 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +14 -10
- package/dest/contracts/chain_state_override.d.ts +38 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +100 -0
- package/dest/contracts/empire_base.d.ts +3 -1
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/fee_asset_price_oracle.d.ts +2 -1
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -1
- package/dest/contracts/fee_asset_price_oracle.js +20 -3
- package/dest/contracts/governance.js +3 -3
- package/dest/contracts/governance_proposer.d.ts +3 -1
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +9 -0
- package/dest/contracts/inbox.d.ts +3 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +11 -6
- package/dest/contracts/index.d.ts +3 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +2 -2
- package/dest/contracts/multicall.d.ts +51 -2
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +85 -0
- package/dest/contracts/registry.d.ts +3 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/registry.js +30 -1
- package/dest/contracts/rollup.d.ts +5014 -25
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +314 -61
- package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +3 -4
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/{tally_slashing_proposer.js → slashing_proposer.js} +13 -15
- package/dest/deploy_aztec_l1_contracts.d.ts +4 -8
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +2 -4
- package/dest/deploy_l1_contract.js +3 -3
- package/dest/generated/l1-contracts-defaults.d.ts +2 -2
- package/dest/generated/l1-contracts-defaults.js +2 -2
- package/dest/l1_artifacts.d.ts +9404 -15792
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +1 -5
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +0 -6
- package/dest/l1_reader.d.ts +3 -1
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +7 -2
- package/dest/l1_tx_utils/config.d.ts +7 -1
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +14 -1
- package/dest/l1_tx_utils/factory.d.ts +18 -10
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +17 -7
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +15 -15
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +9 -15
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -3
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils/index-blobs.js +2 -2
- package/dest/l1_tx_utils/index.d.ts +2 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +20 -7
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +75 -51
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +8 -4
- package/dest/l1_tx_utils/tx_delayer.d.ts +56 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +62 -34
- package/dest/publisher_manager.d.ts +21 -7
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +81 -7
- package/dest/queries.d.ts +13 -2
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +62 -3
- package/dest/test/chain_monitor.d.ts +23 -3
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +38 -2
- package/dest/test/eth_cheat_codes.d.ts +6 -4
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +6 -4
- package/dest/test/index.d.ts +1 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +0 -2
- package/dest/test/rollup_cheat_codes.d.ts +5 -1
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +9 -1
- package/dest/test/start_anvil.d.ts +23 -3
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +143 -29
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/utils.d.ts +1 -1
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +16 -12
- package/package.json +5 -7
- package/src/client.ts +28 -2
- package/src/config.ts +23 -14
- package/src/contracts/chain_state_override.ts +147 -0
- package/src/contracts/empire_base.ts +2 -0
- package/src/contracts/fee_asset_price_oracle.ts +20 -2
- package/src/contracts/governance.ts +3 -3
- package/src/contracts/governance_proposer.ts +6 -0
- package/src/contracts/inbox.ts +12 -4
- package/src/contracts/index.ts +2 -2
- package/src/contracts/multicall.ts +65 -1
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +349 -69
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +14 -16
- package/src/deploy_aztec_l1_contracts.ts +20 -7
- package/src/deploy_l1_contract.ts +3 -3
- package/src/generated/l1-contracts-defaults.ts +2 -2
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +0 -7
- package/src/l1_reader.ts +14 -2
- package/src/l1_tx_utils/config.ts +20 -0
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +43 -54
- package/src/l1_tx_utils/index-blobs.ts +2 -2
- package/src/l1_tx_utils/index.ts +1 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +68 -30
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +8 -4
- package/src/{test → l1_tx_utils}/tx_delayer.ts +78 -50
- package/src/publisher_manager.ts +105 -10
- package/src/queries.ts +70 -4
- package/src/test/chain_monitor.ts +65 -3
- package/src/test/eth_cheat_codes.ts +6 -4
- package/src/test/index.ts +0 -2
- package/src/test/rollup_cheat_codes.ts +11 -1
- package/src/test/start_anvil.ts +177 -29
- package/src/test/upgrade_utils.ts +2 -2
- package/src/utils.ts +17 -14
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -67
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -207
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
- package/dest/test/delayed_tx_utils.d.ts +0 -13
- package/dest/test/delayed_tx_utils.d.ts.map +0 -1
- package/dest/test/delayed_tx_utils.js +0 -28
- package/dest/test/tx_delayer.d.ts +0 -36
- package/dest/test/tx_delayer.d.ts.map +0 -1
- package/src/contracts/empire_slashing_proposer.ts +0 -259
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
package/src/client.ts
CHANGED
|
@@ -25,10 +25,35 @@ type Config = {
|
|
|
25
25
|
l1ChainId: number;
|
|
26
26
|
/** The polling interval viem uses in ms */
|
|
27
27
|
viemPollingIntervalMS?: number;
|
|
28
|
+
/** Timeout for HTTP requests to the L1 RPC node in ms. */
|
|
29
|
+
l1HttpTimeoutMS?: number;
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
export type { Config as EthereumClientConfig };
|
|
31
33
|
|
|
34
|
+
/** Creates a viem fallback HTTP transport for the given L1 RPC URLs. */
|
|
35
|
+
export function makeL1HttpTransport(rpcUrls: string[], opts?: { timeout?: number }) {
|
|
36
|
+
return fallback(rpcUrls.map(url => http(url, { batch: false, timeout: opts?.timeout })));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns the individual RPC URLs underlying a viem public client that was constructed with a
|
|
41
|
+
* fallback HTTP transport (see {@link makeL1HttpTransport}). Returns an empty array if the
|
|
42
|
+
* transport shape is not recognized (e.g. mock clients in tests, or non-fallback transports).
|
|
43
|
+
*/
|
|
44
|
+
export function getRpcUrlsFromClient(client: ViemPublicClient): string[] {
|
|
45
|
+
const transport = client.transport as unknown as {
|
|
46
|
+
transports?: { value?: { url?: string } }[];
|
|
47
|
+
value?: { url?: string };
|
|
48
|
+
url?: string;
|
|
49
|
+
};
|
|
50
|
+
if (Array.isArray(transport?.transports)) {
|
|
51
|
+
return transport.transports.map(t => t?.value?.url).filter((url): url is string => typeof url === 'string');
|
|
52
|
+
}
|
|
53
|
+
const singleUrl = transport?.value?.url ?? transport?.url;
|
|
54
|
+
return typeof singleUrl === 'string' ? [singleUrl] : [];
|
|
55
|
+
}
|
|
56
|
+
|
|
32
57
|
// TODO: Use these methods to abstract the creation of viem clients.
|
|
33
58
|
|
|
34
59
|
/** Returns a viem public client given the L1 config. */
|
|
@@ -36,7 +61,7 @@ export function getPublicClient(config: Config): ViemPublicClient {
|
|
|
36
61
|
const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
37
62
|
return createPublicClient({
|
|
38
63
|
chain: chain.chainInfo,
|
|
39
|
-
transport:
|
|
64
|
+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
|
|
40
65
|
pollingInterval: config.viemPollingIntervalMS,
|
|
41
66
|
});
|
|
42
67
|
}
|
|
@@ -77,6 +102,7 @@ export function createExtendedL1Client(
|
|
|
77
102
|
chain: Chain = foundry,
|
|
78
103
|
pollingIntervalMS?: number,
|
|
79
104
|
addressIndex?: number,
|
|
105
|
+
opts?: { httpTimeoutMS?: number },
|
|
80
106
|
): ExtendedViemWalletClient {
|
|
81
107
|
const hdAccount =
|
|
82
108
|
typeof mnemonicOrPrivateKeyOrHdAccount === 'string'
|
|
@@ -88,7 +114,7 @@ export function createExtendedL1Client(
|
|
|
88
114
|
const extendedClient = createWalletClient({
|
|
89
115
|
account: hdAccount,
|
|
90
116
|
chain,
|
|
91
|
-
transport:
|
|
117
|
+
transport: makeL1HttpTransport(rpcUrls, { timeout: opts?.httpTimeoutMS }),
|
|
92
118
|
pollingInterval: pollingIntervalMS,
|
|
93
119
|
}).extend(publicActions);
|
|
94
120
|
|
package/src/config.ts
CHANGED
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
type ConfigMappingsType,
|
|
3
3
|
bigintConfigHelper,
|
|
4
4
|
booleanConfigHelper,
|
|
5
|
-
enumConfigHelper,
|
|
6
5
|
getConfigFromMappings,
|
|
7
6
|
getDefaultConfig,
|
|
8
7
|
numberConfigHelper,
|
|
8
|
+
omitConfigMappings,
|
|
9
9
|
optionalNumberConfigHelper,
|
|
10
10
|
} from '@aztec/foundation/config';
|
|
11
11
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -18,6 +18,8 @@ export type GenesisStateConfig = {
|
|
|
18
18
|
testAccounts: boolean;
|
|
19
19
|
/** Whether to populate the genesis state with initial fee juice for the sponsored FPC */
|
|
20
20
|
sponsoredFPC: boolean;
|
|
21
|
+
/** Additional addresses to prefund with fee juice at genesis */
|
|
22
|
+
prefundAddresses: string[];
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
export type L1ContractsConfig = {
|
|
@@ -57,13 +59,13 @@ export type L1ContractsConfig = {
|
|
|
57
59
|
slashingOffsetInRounds: number;
|
|
58
60
|
/** How long slashing can be disabled for in seconds when vetoer disables it */
|
|
59
61
|
slashingDisableDuration: number;
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
/** Minimum amount that can be slashed
|
|
62
|
+
/** Whether to deploy a slasher proposer */
|
|
63
|
+
slasherEnabled: boolean;
|
|
64
|
+
/** Minimum amount that can be slashed */
|
|
63
65
|
slashAmountSmall: bigint;
|
|
64
|
-
/** Medium amount to slash
|
|
66
|
+
/** Medium amount to slash */
|
|
65
67
|
slashAmountMedium: bigint;
|
|
66
|
-
/** Largest amount that can be slashed per round
|
|
68
|
+
/** Largest amount that can be slashed per round */
|
|
67
69
|
slashAmountLarge: bigint;
|
|
68
70
|
/** Governance proposing quorum (defaults to roundSize/2 + 1) */
|
|
69
71
|
governanceProposerQuorum?: number;
|
|
@@ -149,13 +151,10 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
149
151
|
'How many slashing rounds back we slash (ie when slashing in round N, we slash for offenses committed during epochs of round N-offset)',
|
|
150
152
|
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_SLASHING_OFFSET_IN_ROUNDS),
|
|
151
153
|
},
|
|
152
|
-
|
|
153
|
-
env: '
|
|
154
|
-
description: '
|
|
155
|
-
...
|
|
156
|
-
['empire', 'tally', 'none'] as const,
|
|
157
|
-
l1ContractsDefaultEnv.AZTEC_SLASHER_FLAVOR as 'empire' | 'tally' | 'none',
|
|
158
|
-
),
|
|
154
|
+
slasherEnabled: {
|
|
155
|
+
env: 'AZTEC_SLASHER_ENABLED',
|
|
156
|
+
description: 'Whether to deploy a slasher proposer',
|
|
157
|
+
...booleanConfigHelper(true),
|
|
159
158
|
},
|
|
160
159
|
slashAmountSmall: {
|
|
161
160
|
env: 'AZTEC_SLASH_AMOUNT_SMALL',
|
|
@@ -238,7 +237,7 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
238
237
|
description: 'The delay before a validator can exit the set',
|
|
239
238
|
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_EXIT_DELAY_SECONDS),
|
|
240
239
|
},
|
|
241
|
-
...l1TxUtilsConfigMappings,
|
|
240
|
+
...omitConfigMappings(l1TxUtilsConfigMappings, ['ethereumSlotDuration']),
|
|
242
241
|
};
|
|
243
242
|
|
|
244
243
|
/**
|
|
@@ -258,6 +257,16 @@ export const genesisStateConfigMappings: ConfigMappingsType<GenesisStateConfig>
|
|
|
258
257
|
description: 'Whether to populate the genesis state with initial fee juice for the sponsored FPC.',
|
|
259
258
|
...booleanConfigHelper(false),
|
|
260
259
|
},
|
|
260
|
+
prefundAddresses: {
|
|
261
|
+
env: 'PREFUND_ADDRESSES',
|
|
262
|
+
description: 'Comma-separated list of Aztec addresses to prefund with fee juice at genesis (local network only).',
|
|
263
|
+
parseEnv: (val: string) =>
|
|
264
|
+
val
|
|
265
|
+
.split(',')
|
|
266
|
+
.map(a => a.trim())
|
|
267
|
+
.filter(a => a.length > 0),
|
|
268
|
+
defaultValue: [],
|
|
269
|
+
},
|
|
261
270
|
};
|
|
262
271
|
|
|
263
272
|
export function getL1ContractsConfigEnvVars(): L1ContractsConfig {
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
2
|
+
import type { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
+
|
|
5
|
+
import type { StateOverride } from 'viem';
|
|
6
|
+
|
|
7
|
+
import { type FeeHeader, RollupContract } from './rollup.js';
|
|
8
|
+
|
|
9
|
+
export type PendingCheckpointOverrideState = {
|
|
10
|
+
archive?: Fr;
|
|
11
|
+
feeHeader?: FeeHeader;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** Describes the simulated L1 rollup state that downstream calls should observe. */
|
|
15
|
+
export type SimulationOverridesPlan = {
|
|
16
|
+
pendingCheckpointNumber?: CheckpointNumber;
|
|
17
|
+
pendingCheckpointState?: PendingCheckpointOverrideState;
|
|
18
|
+
disableBlobCheck?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Builds a single-checkpoint simulation plan before it is translated into a viem state override. */
|
|
22
|
+
export class SimulationOverridesBuilder {
|
|
23
|
+
private pendingCheckpointNumber?: CheckpointNumber;
|
|
24
|
+
private pendingCheckpointState?: PendingCheckpointOverrideState;
|
|
25
|
+
private disableBlobCheck = false;
|
|
26
|
+
|
|
27
|
+
/** Starts from an existing plan so callers can extend or specialize it. */
|
|
28
|
+
public static from(plan: SimulationOverridesPlan | undefined): SimulationOverridesBuilder {
|
|
29
|
+
return new SimulationOverridesBuilder().merge(plan);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Merges another plan into this builder. Later values win. */
|
|
33
|
+
public merge(plan: SimulationOverridesPlan | undefined): this {
|
|
34
|
+
if (!plan) {
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.pendingCheckpointNumber = plan.pendingCheckpointNumber;
|
|
39
|
+
this.pendingCheckpointState = plan.pendingCheckpointState
|
|
40
|
+
? { ...(this.pendingCheckpointState ?? {}), ...plan.pendingCheckpointState }
|
|
41
|
+
: this.pendingCheckpointState;
|
|
42
|
+
this.disableBlobCheck = this.disableBlobCheck || (plan.disableBlobCheck ?? false);
|
|
43
|
+
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Sets the checkpoint number that archive and fee header overrides should attach to. */
|
|
48
|
+
public forPendingCheckpoint(pendingCheckpointNumber: CheckpointNumber | undefined): this {
|
|
49
|
+
this.pendingCheckpointNumber = pendingCheckpointNumber;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Overrides the archive root for the configured pending checkpoint. */
|
|
54
|
+
public withPendingArchive(archive: Fr): this {
|
|
55
|
+
this.assertPendingCheckpointNumber();
|
|
56
|
+
this.pendingCheckpointState = { ...(this.pendingCheckpointState ?? {}), archive };
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Overrides the fee header for the configured pending checkpoint. */
|
|
61
|
+
public withPendingFeeHeader(feeHeader: FeeHeader): this {
|
|
62
|
+
this.assertPendingCheckpointNumber();
|
|
63
|
+
this.pendingCheckpointState = { ...(this.pendingCheckpointState ?? {}), feeHeader };
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Disables blob checking for simulations that cannot provide DA inputs. */
|
|
68
|
+
public withoutBlobCheck(): this {
|
|
69
|
+
this.disableBlobCheck = true;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Builds the final plan, or `undefined` when no overrides were configured. */
|
|
74
|
+
public build(): SimulationOverridesPlan | undefined {
|
|
75
|
+
if (!this.pendingCheckpointState && this.pendingCheckpointNumber === undefined && !this.disableBlobCheck) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
pendingCheckpointNumber: this.pendingCheckpointNumber,
|
|
81
|
+
pendingCheckpointState: this.pendingCheckpointState,
|
|
82
|
+
disableBlobCheck: this.disableBlobCheck || undefined,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private assertPendingCheckpointNumber(): void {
|
|
87
|
+
if (this.pendingCheckpointNumber === undefined) {
|
|
88
|
+
throw new Error('pendingCheckpointNumber must be set before attaching archive or fee header overrides');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Translates a simulation plan into the viem state override shape expected by rollup calls. */
|
|
94
|
+
export async function buildSimulationOverridesStateOverride(
|
|
95
|
+
rollup: RollupContract,
|
|
96
|
+
plan: SimulationOverridesPlan | undefined,
|
|
97
|
+
): Promise<StateOverride> {
|
|
98
|
+
if (!plan) {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const rollupStateDiff: NonNullable<StateOverride[number]['stateDiff']> = [];
|
|
103
|
+
|
|
104
|
+
if (plan.pendingCheckpointNumber !== undefined) {
|
|
105
|
+
rollupStateDiff.push(
|
|
106
|
+
...extractRollupStateDiff(await rollup.makePendingCheckpointNumberOverride(plan.pendingCheckpointNumber)),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (plan.pendingCheckpointState && plan.pendingCheckpointNumber === undefined) {
|
|
111
|
+
throw new Error('pendingCheckpointState requires pendingCheckpointNumber to be set');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (plan.pendingCheckpointState?.archive) {
|
|
115
|
+
rollupStateDiff.push(
|
|
116
|
+
...extractRollupStateDiff(
|
|
117
|
+
rollup.makeArchiveOverride(plan.pendingCheckpointNumber!, plan.pendingCheckpointState.archive),
|
|
118
|
+
),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (plan.pendingCheckpointState?.feeHeader) {
|
|
123
|
+
rollupStateDiff.push(
|
|
124
|
+
...extractRollupStateDiff(
|
|
125
|
+
await rollup.makeFeeHeaderOverride(plan.pendingCheckpointNumber!, plan.pendingCheckpointState.feeHeader),
|
|
126
|
+
),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (plan.disableBlobCheck) {
|
|
131
|
+
rollupStateDiff.push({
|
|
132
|
+
slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true),
|
|
133
|
+
value: toPaddedHex(0n, true),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (rollupStateDiff.length === 0) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return [{ address: rollup.address, stateDiff: rollupStateDiff }];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function extractRollupStateDiff(override: StateOverride | StateOverride[number] | undefined) {
|
|
145
|
+
const entries = Array.isArray(override) ? override : override ? [override] : [];
|
|
146
|
+
return entries.flatMap(entry => entry.stateDiff ?? []);
|
|
147
|
+
}
|
|
@@ -22,6 +22,8 @@ export interface IEmpireBase {
|
|
|
22
22
|
signerAddress: Hex,
|
|
23
23
|
signer: (msg: TypedDataDefinition) => Promise<Hex>,
|
|
24
24
|
): Promise<L1TxRequest>;
|
|
25
|
+
/** Checks if a payload was ever submitted to governance via submitRoundWinner. */
|
|
26
|
+
hasPayloadBeenProposed(payload: Hex, fromBlock: bigint): Promise<boolean>;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export function encodeSignal(payload: Hex): Hex {
|
|
@@ -34,12 +34,25 @@ export class FeeAssetPriceOracle {
|
|
|
34
34
|
|
|
35
35
|
@memoize
|
|
36
36
|
async getUniswapOracle(): Promise<UniswapPriceOracle | undefined> {
|
|
37
|
-
|
|
37
|
+
const code = await this.client.getCode({ address: STATE_VIEW_ADDRESS.toString() });
|
|
38
|
+
if (code === undefined || code === '0x') {
|
|
38
39
|
this.log.warn('Uniswap V4 StateView contract not found, skipping fee asset price oracle');
|
|
39
40
|
return undefined;
|
|
40
41
|
}
|
|
41
42
|
this.log.info('Uniswap V4 StateView contract found, initializing fee asset price oracle');
|
|
42
|
-
|
|
43
|
+
const oracle = new UniswapPriceOracle(this.client, this.log);
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
if (!(await oracle.isPoolInitialized())) {
|
|
47
|
+
this.log.warn('Uniswap V4 pool not initialized, skipping fee asset price oracle');
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
this.log.warn(`Failed to check if Uniswap V4 pool is initialized: ${err}`);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return oracle;
|
|
43
56
|
}
|
|
44
57
|
|
|
45
58
|
/**
|
|
@@ -210,6 +223,11 @@ class UniswapPriceOracle {
|
|
|
210
223
|
return keccak256(encoded);
|
|
211
224
|
}
|
|
212
225
|
|
|
226
|
+
async isPoolInitialized(): Promise<boolean> {
|
|
227
|
+
const [sqrtPriceX96] = await this.stateView.read.getSlot0([this.poolId], undefined);
|
|
228
|
+
return sqrtPriceX96 !== 0n;
|
|
229
|
+
}
|
|
230
|
+
|
|
213
231
|
/**
|
|
214
232
|
* Gets the price as ETH per FeeAsset, scaled by 1e12.
|
|
215
233
|
* This is the format expected by the rollup contract.
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from 'viem';
|
|
15
15
|
|
|
16
16
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
17
|
-
import {
|
|
17
|
+
import { createL1TxUtils } from '../l1_tx_utils/index.js';
|
|
18
18
|
import { type ExtendedViemWalletClient, type ViemClient, isExtendedClient } from '../types.js';
|
|
19
19
|
|
|
20
20
|
export type L1GovernanceContractAddresses = Pick<
|
|
@@ -194,7 +194,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
|
|
|
194
194
|
retries: number;
|
|
195
195
|
logger: Logger;
|
|
196
196
|
}) {
|
|
197
|
-
const l1TxUtils =
|
|
197
|
+
const l1TxUtils = createL1TxUtils(this.client, { logger });
|
|
198
198
|
const retryDelaySeconds = 12;
|
|
199
199
|
|
|
200
200
|
voteAmount = voteAmount ?? (await this.getPowerForProposal(proposalId));
|
|
@@ -252,7 +252,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
|
|
|
252
252
|
retries: number;
|
|
253
253
|
logger: Logger;
|
|
254
254
|
}) {
|
|
255
|
-
const l1TxUtils =
|
|
255
|
+
const l1TxUtils = createL1TxUtils(this.client, { logger });
|
|
256
256
|
const retryDelaySeconds = 12;
|
|
257
257
|
let success = false;
|
|
258
258
|
for (let i = 0; i < retries; i++) {
|
|
@@ -110,6 +110,12 @@ export class GovernanceProposerContract implements IEmpireBase {
|
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/** Checks if a payload was ever submitted to governance via submitRoundWinner. */
|
|
114
|
+
public async hasPayloadBeenProposed(payload: Hex, fromBlock: bigint): Promise<boolean> {
|
|
115
|
+
const events = await this.proposer.getEvents.PayloadSubmitted({ payload }, { fromBlock, strict: true });
|
|
116
|
+
return events.length > 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
public async submitRoundWinner(
|
|
114
120
|
round: bigint,
|
|
115
121
|
l1TxUtils: L1TxUtils,
|
package/src/contracts/inbox.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { maxBigint } from '@aztec/foundation/bigint';
|
|
1
2
|
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
3
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
@@ -82,10 +83,17 @@ export class InboxContract {
|
|
|
82
83
|
.map(log => this.mapMessageSentLog(log));
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
/** Fetches MessageSent events for a specific message hash
|
|
86
|
-
async getMessageSentEventByHash(
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
/** Fetches MessageSent events for a specific message hash around a specific block. */
|
|
87
|
+
async getMessageSentEventByHash(msgHash: Hex, aroundL1BlockNumber: bigint): Promise<MessageSentLog> {
|
|
88
|
+
// We don't use blockHash here because we don't want the query to throw if the L1 block number no longer exists on chain
|
|
89
|
+
// due to an L1 reorg. The use case for this method is usually checking if a message still exists on the Inbox after
|
|
90
|
+
// a reorg, so it's possible the message was moved one block up or down, and that the original L1 block where we
|
|
91
|
+
// saw it no longer exists, rendering the block-by-hash approach invalid.
|
|
92
|
+
const [log] = await this.inbox.getEvents.MessageSent(
|
|
93
|
+
{ hash: msgHash },
|
|
94
|
+
{ fromBlock: maxBigint(aroundL1BlockNumber - 5n, 1n), toBlock: aroundL1BlockNumber + 5n },
|
|
95
|
+
);
|
|
96
|
+
return log && this.mapMessageSentLog(log);
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
private mapMessageSentLog(log: {
|
package/src/contracts/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './chain_state_override.js';
|
|
1
2
|
export * from './empire_base.js';
|
|
2
3
|
export * from './errors.js';
|
|
3
4
|
export * from './fee_asset_handler.js';
|
|
@@ -12,6 +13,5 @@ export * from './multicall.js';
|
|
|
12
13
|
export * from './outbox.js';
|
|
13
14
|
export * from './registry.js';
|
|
14
15
|
export * from './rollup.js';
|
|
15
|
-
export * from './
|
|
16
|
-
export * from './tally_slashing_proposer.js';
|
|
16
|
+
export * from './slashing_proposer.js';
|
|
17
17
|
export * from './slasher_contract.js';
|
|
@@ -2,7 +2,7 @@ import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
|
2
2
|
import { TimeoutError } from '@aztec/foundation/error';
|
|
3
3
|
import type { Logger } from '@aztec/foundation/log';
|
|
4
4
|
|
|
5
|
-
import { type EncodeFunctionDataParameters, type Hex, encodeFunctionData, multicall3Abi } from 'viem';
|
|
5
|
+
import { type Address, type EncodeFunctionDataParameters, type Hex, encodeFunctionData, multicall3Abi } from 'viem';
|
|
6
6
|
|
|
7
7
|
import type { L1BlobInputs, L1TxConfig, L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
8
8
|
import type { ExtendedViemWalletClient } from '../types.js';
|
|
@@ -11,6 +11,39 @@ import { RollupContract } from './rollup.js';
|
|
|
11
11
|
|
|
12
12
|
export const MULTI_CALL_3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11' as const;
|
|
13
13
|
|
|
14
|
+
/** ABI fragment for aggregate3Value — not included in viem's multicall3Abi. */
|
|
15
|
+
export const aggregate3ValueAbi = [
|
|
16
|
+
{
|
|
17
|
+
inputs: [
|
|
18
|
+
{
|
|
19
|
+
components: [
|
|
20
|
+
{ internalType: 'address', name: 'target', type: 'address' },
|
|
21
|
+
{ internalType: 'bool', name: 'allowFailure', type: 'bool' },
|
|
22
|
+
{ internalType: 'uint256', name: 'value', type: 'uint256' },
|
|
23
|
+
{ internalType: 'bytes', name: 'callData', type: 'bytes' },
|
|
24
|
+
],
|
|
25
|
+
internalType: 'struct Multicall3.Call3Value[]',
|
|
26
|
+
name: 'calls',
|
|
27
|
+
type: 'tuple[]',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
name: 'aggregate3Value',
|
|
31
|
+
outputs: [
|
|
32
|
+
{
|
|
33
|
+
components: [
|
|
34
|
+
{ internalType: 'bool', name: 'success', type: 'bool' },
|
|
35
|
+
{ internalType: 'bytes', name: 'returnData', type: 'bytes' },
|
|
36
|
+
],
|
|
37
|
+
internalType: 'struct Multicall3.Result[]',
|
|
38
|
+
name: 'returnData',
|
|
39
|
+
type: 'tuple[]',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
stateMutability: 'payable',
|
|
43
|
+
type: 'function',
|
|
44
|
+
},
|
|
45
|
+
] as const;
|
|
46
|
+
|
|
14
47
|
export class Multicall3 {
|
|
15
48
|
static async forward(
|
|
16
49
|
requests: L1TxRequest[],
|
|
@@ -122,6 +155,37 @@ export class Multicall3 {
|
|
|
122
155
|
throw err;
|
|
123
156
|
}
|
|
124
157
|
}
|
|
158
|
+
|
|
159
|
+
/** Batch multiple value transfers into a single aggregate3Value call on Multicall3. */
|
|
160
|
+
static async forwardValue(calls: { to: Address; value: bigint }[], l1TxUtils: L1TxUtils, logger: Logger) {
|
|
161
|
+
const args = calls.map(c => ({
|
|
162
|
+
target: c.to,
|
|
163
|
+
allowFailure: false,
|
|
164
|
+
value: c.value,
|
|
165
|
+
callData: '0x' as Hex,
|
|
166
|
+
}));
|
|
167
|
+
|
|
168
|
+
const data = encodeFunctionData({
|
|
169
|
+
abi: aggregate3ValueAbi,
|
|
170
|
+
functionName: 'aggregate3Value',
|
|
171
|
+
args: [args],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const totalValue = calls.reduce((sum, c) => sum + c.value, 0n);
|
|
175
|
+
|
|
176
|
+
logger.info(`Sending aggregate3Value with ${calls.length} calls`, { totalValue });
|
|
177
|
+
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
|
|
178
|
+
to: MULTI_CALL_3_ADDRESS,
|
|
179
|
+
data,
|
|
180
|
+
value: totalValue,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
if (receipt.status !== 'success') {
|
|
184
|
+
throw new Error(`aggregate3Value transaction reverted: ${receipt.transactionHash}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return { receipt };
|
|
188
|
+
}
|
|
125
189
|
}
|
|
126
190
|
|
|
127
191
|
export async function deployMulticall3(l1Client: ExtendedViemWalletClient, logger: Logger) {
|
|
@@ -3,7 +3,7 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
3
3
|
import { RegistryAbi } from '@aztec/l1-artifacts/RegistryAbi';
|
|
4
4
|
import { TestERC20Abi } from '@aztec/l1-artifacts/TestERC20Abi';
|
|
5
5
|
|
|
6
|
-
import { type GetContractReturnType, type Hex, getContract } from 'viem';
|
|
6
|
+
import { type GetContractReturnType, type Hex, getAbiItem, getContract } from 'viem';
|
|
7
7
|
|
|
8
8
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
9
9
|
import type { ViemClient } from '../types.js';
|
|
@@ -128,4 +128,34 @@ export class RegistryContract {
|
|
|
128
128
|
public async getRewardDistributor(): Promise<EthAddress> {
|
|
129
129
|
return EthAddress.fromString(await this.registry.read.getRewardDistributor());
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
/** Returns the L1 timestamp at which the given rollup was registered via addRollup(). */
|
|
133
|
+
public async getCanonicalRollupRegistrationTimestamp(
|
|
134
|
+
rollupAddress: EthAddress,
|
|
135
|
+
fromBlock?: bigint,
|
|
136
|
+
): Promise<bigint | undefined> {
|
|
137
|
+
const event = getAbiItem({ abi: RegistryAbi, name: 'CanonicalRollupUpdated' });
|
|
138
|
+
const start = fromBlock ?? 0n;
|
|
139
|
+
const latestBlock = await this.client.getBlockNumber();
|
|
140
|
+
const chunkSize = 1_000n;
|
|
141
|
+
|
|
142
|
+
for (let from = start; from <= latestBlock; from += chunkSize) {
|
|
143
|
+
const to = from + chunkSize - 1n > latestBlock ? latestBlock : from + chunkSize - 1n;
|
|
144
|
+
const logs = await this.client.getLogs({
|
|
145
|
+
address: this.address.toString(),
|
|
146
|
+
fromBlock: from,
|
|
147
|
+
toBlock: to,
|
|
148
|
+
strict: true,
|
|
149
|
+
event,
|
|
150
|
+
args: { instance: rollupAddress.toString() },
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
if (logs.length > 0) {
|
|
154
|
+
const block = await this.client.getBlock({ blockNumber: logs[0].blockNumber });
|
|
155
|
+
return block.timestamp;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
131
161
|
}
|