Skip to content

Commit 379759b

Browse files
committed
feat: fetch addresses from registry
1 parent 17e79f4 commit 379759b

File tree

14 files changed

+646
-160
lines changed

14 files changed

+646
-160
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity >=0.8.27;
3+
4+
import {IPayload} from "@aztec/governance/interfaces/IPayload.sol";
5+
import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol";
6+
7+
/**
8+
* @title RegisterNewRollupVersionPayload
9+
* @author Aztec Labs
10+
* @notice A payload that registers a new rollup version.
11+
*/
12+
contract RegisterNewRollupVersionPayload is IPayload {
13+
IRegistry public immutable REGISTRY;
14+
address public immutable ROLLUP;
15+
16+
constructor(IRegistry _registry, address _rollup) {
17+
REGISTRY = _registry;
18+
ROLLUP = _rollup;
19+
}
20+
21+
function getActions() external view override(IPayload) returns (IPayload.Action[] memory) {
22+
IPayload.Action[] memory res = new IPayload.Action[](1);
23+
24+
res[0] = Action({
25+
target: address(REGISTRY),
26+
data: abi.encodeWithSelector(IRegistry.upgrade.selector, ROLLUP)
27+
});
28+
29+
return res;
30+
}
31+
}

spartan/aztec-network/files/config/config-prover-env.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ coin_issuer_address=$(echo "$output" | grep -oP 'CoinIssuer Address: \K0x[a-fA-F
1919
reward_distributor_address=$(echo "$output" | grep -oP 'RewardDistributor Address: \K0x[a-fA-F0-9]{40}')
2020
governance_proposer_address=$(echo "$output" | grep -oP 'GovernanceProposer Address: \K0x[a-fA-F0-9]{40}')
2121
governance_address=$(echo "$output" | grep -oP 'Governance Address: \K0x[a-fA-F0-9]{40}')
22-
slash_factory_address=$(echo "$output" | grep -oP 'SlashFactory Address: \K0x[a-fA-F0-9]{40}')
2322

2423
# Write the addresses to a file in the shared volume
2524
cat <<EOF >/shared/contracts/contracts.env
@@ -35,7 +34,6 @@ export COIN_ISSUER_CONTRACT_ADDRESS=$coin_issuer_address
3534
export REWARD_DISTRIBUTOR_CONTRACT_ADDRESS=$reward_distributor_address
3635
export GOVERNANCE_PROPOSER_CONTRACT_ADDRESS=$governance_proposer_address
3736
export GOVERNANCE_CONTRACT_ADDRESS=$governance_address
38-
export SLASH_FACTORY_CONTRACT_ADDRESS=$slash_factory_address
3937
EOF
4038

4139
cat /shared/contracts/contracts.env

yarn-project/aztec.js/src/contract/contract.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ describe('Contract Class', () => {
4848
coinIssuerAddress: EthAddress.random(),
4949
rewardDistributorAddress: EthAddress.random(),
5050
governanceProposerAddress: EthAddress.random(),
51-
slashFactoryAddress: EthAddress.random(),
5251
};
5352

5453
const defaultArtifact: ContractArtifact = {

yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,5 @@ export async function deployL1Contracts(
5858
log(`RewardDistributor Address: ${l1ContractAddresses.rewardDistributorAddress.toString()}`);
5959
log(`GovernanceProposer Address: ${l1ContractAddresses.governanceProposerAddress.toString()}`);
6060
log(`Governance Address: ${l1ContractAddresses.governanceAddress.toString()}`);
61-
log(`SlashFactory Address: ${l1ContractAddresses.slashFactoryAddress.toString()}`);
6261
}
6362
}

yarn-project/cli/src/cmds/pxe/get_node_info.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export async function getNodeInfo(
3434
rewardDistributor: info.l1ContractAddresses.rewardDistributorAddress.toString(),
3535
governanceProposer: info.l1ContractAddresses.governanceProposerAddress.toString(),
3636
governance: info.l1ContractAddresses.governanceAddress.toString(),
37-
slashFactory: info.l1ContractAddresses.slashFactoryAddress.toString(),
37+
slashFactory: info.l1ContractAddresses.slashFactoryAddress?.toString(),
3838
},
3939
protocolContractAddresses: {
4040
classRegisterer: info.protocolContractAddresses.classRegisterer.toString(),
@@ -60,7 +60,7 @@ export async function getNodeInfo(
6060
log(` RewardDistributor Address: ${info.l1ContractAddresses.rewardDistributorAddress.toString()}`);
6161
log(` GovernanceProposer Address: ${info.l1ContractAddresses.governanceProposerAddress.toString()}`);
6262
log(` Governance Address: ${info.l1ContractAddresses.governanceAddress.toString()}`);
63-
log(` SlashFactory Address: ${info.l1ContractAddresses.slashFactoryAddress.toString()}`);
63+
log(` SlashFactory Address: ${info.l1ContractAddresses.slashFactoryAddress?.toString()}`);
6464

6565
log(`L2 Contract Addresses:`);
6666
log(` Class Registerer: ${info.protocolContractAddresses.classRegisterer.toString()}`);

yarn-project/end-to-end/src/e2e_p2p/slashing.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ describe('e2e_p2p_slashing', () => {
8383
});
8484

8585
const slashFactory = getContract({
86-
address: getAddress(t.ctx.deployL1ContractsValues.l1ContractAddresses.slashFactoryAddress.toString()),
86+
address: getAddress(t.ctx.deployL1ContractsValues.l1ContractAddresses.slashFactoryAddress!.toString()),
8787
abi: SlashFactoryAbi,
8888
client: t.ctx.deployL1ContractsValues.publicClient,
8989
});

yarn-project/ethereum/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@viem/anvil": "^0.0.10",
5050
"get-port": "^7.1.0",
5151
"jest": "^29.5.0",
52+
"lodash.omit": "^4.5.0",
5253
"ts-node": "^10.9.1",
5354
"typescript": "^5.0.4"
5455
},
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
import { Fr } from '@aztec/foundation/fields';
2+
import { type Logger, createLogger } from '@aztec/foundation/log';
3+
import { TestERC20Abi as FeeJuiceAbi, GovernanceAbi } from '@aztec/l1-artifacts';
4+
5+
import { type Anvil } from '@viem/anvil';
6+
import omit from 'lodash.omit';
7+
import { getContract } from 'viem';
8+
import { type PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts';
9+
import { foundry } from 'viem/chains';
10+
11+
import { DefaultL1ContractsConfig } from '../config.js';
12+
import { createL1Clients, deployL1Contracts, deployRollupAndPeriphery } from '../deploy_l1_contracts.js';
13+
import { EthCheatCodes } from '../eth_cheat_codes.js';
14+
import { type L1ContractAddresses } from '../l1_contract_addresses.js';
15+
import { defaultL1TxUtilsConfig } from '../l1_tx_utils.js';
16+
import { startAnvil } from '../test/start_anvil.js';
17+
import type { L1Clients } from '../types.js';
18+
import { RegistryContract } from './registry.js';
19+
20+
const originalVersionSalt = 42;
21+
22+
describe('Registry', () => {
23+
let anvil: Anvil;
24+
let rpcUrl: string;
25+
let privateKey: PrivateKeyAccount;
26+
let logger: Logger;
27+
28+
let vkTreeRoot: Fr;
29+
let protocolContractTreeRoot: Fr;
30+
let l2FeeJuiceAddress: Fr;
31+
let publicClient: L1Clients['publicClient'];
32+
let walletClient: L1Clients['walletClient'];
33+
let registry: RegistryContract;
34+
let deployedAddresses: L1ContractAddresses;
35+
36+
beforeAll(async () => {
37+
logger = createLogger('ethereum:test:registry');
38+
// this is the 6th address that gets funded by the junk mnemonic
39+
privateKey = privateKeyToAccount('0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba');
40+
vkTreeRoot = Fr.random();
41+
protocolContractTreeRoot = Fr.random();
42+
l2FeeJuiceAddress = Fr.random();
43+
44+
({ anvil, rpcUrl } = await startAnvil());
45+
46+
({ publicClient, walletClient } = createL1Clients(rpcUrl, privateKey));
47+
48+
const deployed = await deployL1Contracts(rpcUrl, privateKey, foundry, logger, {
49+
...DefaultL1ContractsConfig,
50+
salt: originalVersionSalt,
51+
vkTreeRoot,
52+
protocolContractTreeRoot,
53+
l2FeeJuiceAddress,
54+
genesisArchiveRoot: Fr.random(),
55+
genesisBlockHash: Fr.random(),
56+
});
57+
// Since the registry cannot "see" the slash factory, we omit it from the addresses for this test
58+
deployedAddresses = omit(deployed.l1ContractAddresses, 'slashFactoryAddress');
59+
registry = new RegistryContract(publicClient, deployedAddresses.registryAddress);
60+
});
61+
62+
afterAll(async () => {
63+
await anvil.stop();
64+
});
65+
66+
it('gets rollup versions', async () => {
67+
const rollupAddress = deployedAddresses.rollupAddress;
68+
{
69+
const address = await registry.getCanonicalAddress();
70+
expect(address).toEqual(rollupAddress);
71+
}
72+
{
73+
const address = await registry.getRollupAddress('canonical');
74+
expect(address).toEqual(rollupAddress);
75+
}
76+
{
77+
const address = await registry.getRollupAddress(1);
78+
expect(address).toEqual(rollupAddress);
79+
}
80+
});
81+
82+
it('handles non-existent versions', async () => {
83+
const address = await registry.getRollupAddress(2);
84+
expect(address).toBeUndefined();
85+
});
86+
87+
it('collects addresses', async () => {
88+
await expect(
89+
RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 'canonical'),
90+
).resolves.toEqual(deployedAddresses);
91+
92+
await expect(
93+
RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 1),
94+
).resolves.toEqual(deployedAddresses);
95+
96+
// Version 2 does not exist
97+
98+
await expect(RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 2)).rejects.toThrow(
99+
'Rollup address is undefined',
100+
);
101+
102+
await expect(
103+
RegistryContract.collectAddressesSafe(publicClient, deployedAddresses.registryAddress, 2),
104+
).resolves.toEqual({
105+
governanceAddress: deployedAddresses.governanceAddress,
106+
governanceProposerAddress: deployedAddresses.governanceProposerAddress,
107+
registryAddress: deployedAddresses.registryAddress,
108+
});
109+
});
110+
111+
it('adds a version to the registry', async () => {
112+
const addresses = await RegistryContract.collectAddresses(
113+
publicClient,
114+
deployedAddresses.registryAddress,
115+
'canonical',
116+
);
117+
const newVersionSalt = originalVersionSalt + 1;
118+
119+
const { rollup: newRollup, payloadAddress } = await deployRollupAndPeriphery(
120+
rpcUrl,
121+
foundry,
122+
privateKey,
123+
{
124+
...DefaultL1ContractsConfig,
125+
salt: newVersionSalt,
126+
vkTreeRoot,
127+
protocolContractTreeRoot,
128+
l2FeeJuiceAddress,
129+
genesisArchiveRoot: Fr.random(),
130+
genesisBlockHash: Fr.random(),
131+
},
132+
{
133+
feeJuicePortalAddress: addresses.feeJuicePortalAddress,
134+
rewardDistributorAddress: addresses.rewardDistributorAddress,
135+
stakingAssetAddress: addresses.stakingAssetAddress,
136+
registryAddress: deployedAddresses.registryAddress,
137+
},
138+
logger,
139+
defaultL1TxUtilsConfig,
140+
);
141+
142+
const { governance, voteAmount } = await createGovernanceProposal(
143+
payloadAddress.toString(),
144+
addresses,
145+
privateKey,
146+
publicClient,
147+
logger,
148+
);
149+
150+
await executeGovernanceProposal(0n, governance, voteAmount, privateKey, publicClient, walletClient, rpcUrl, logger);
151+
152+
const newAddresses = await newRollup.getRollupAddresses();
153+
154+
const newCanonicalAddresses = await RegistryContract.collectAddresses(
155+
publicClient,
156+
deployedAddresses.registryAddress,
157+
'canonical',
158+
);
159+
160+
expect(newCanonicalAddresses).toEqual({
161+
...deployedAddresses,
162+
...newAddresses,
163+
});
164+
165+
await expect(
166+
RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 2),
167+
).resolves.toEqual(newCanonicalAddresses);
168+
169+
await expect(
170+
RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 1),
171+
).resolves.toEqual(deployedAddresses);
172+
});
173+
});
174+
175+
async function executeGovernanceProposal(
176+
proposalId: bigint,
177+
governance: any,
178+
voteAmount: bigint,
179+
privateKey: PrivateKeyAccount,
180+
publicClient: L1Clients['publicClient'],
181+
walletClient: L1Clients['walletClient'],
182+
rpcUrl: string,
183+
logger: Logger,
184+
) {
185+
const proposal = await governance.read.getProposal([proposalId]);
186+
187+
const waitL1Block = async () => {
188+
await publicClient.waitForTransactionReceipt({
189+
hash: await walletClient.sendTransaction({
190+
to: privateKey.address,
191+
value: 1n,
192+
account: privateKey,
193+
}),
194+
});
195+
};
196+
197+
const cheatCodes = new EthCheatCodes(rpcUrl, logger);
198+
199+
const timeToActive = proposal.creation + proposal.config.votingDelay;
200+
logger.info(`Warping to ${timeToActive + 1n}`);
201+
await cheatCodes.warp(Number(timeToActive + 1n));
202+
logger.info(`Warped to ${timeToActive + 1n}`);
203+
await waitL1Block();
204+
205+
logger.info(`Voting`);
206+
const voteTx = await governance.write.vote([proposalId, voteAmount, true], { account: privateKey });
207+
await publicClient.waitForTransactionReceipt({ hash: voteTx });
208+
logger.info(`Voted`);
209+
210+
const timeToExecutable = timeToActive + proposal.config.votingDuration + proposal.config.executionDelay + 1n;
211+
logger.info(`Warping to ${timeToExecutable}`);
212+
await cheatCodes.warp(Number(timeToExecutable));
213+
logger.info(`Warped to ${timeToExecutable}`);
214+
await waitL1Block();
215+
216+
const executeTx = await governance.write.execute([proposalId], { account: privateKey });
217+
await publicClient.waitForTransactionReceipt({ hash: executeTx });
218+
logger.info(`Executed proposal`);
219+
}
220+
221+
async function createGovernanceProposal(
222+
payloadAddress: `0x${string}`,
223+
addresses: L1ContractAddresses,
224+
privateKey: PrivateKeyAccount,
225+
publicClient: L1Clients['publicClient'],
226+
logger: Logger,
227+
) {
228+
const token = getContract({
229+
address: addresses.feeJuiceAddress.toString(),
230+
abi: FeeJuiceAbi,
231+
client: publicClient,
232+
});
233+
234+
const governance = getContract({
235+
address: addresses.governanceAddress.toString(),
236+
abi: GovernanceAbi,
237+
client: publicClient,
238+
});
239+
240+
const lockAmount = 10000n * 10n ** 18n;
241+
const voteAmount = 10000n * 10n ** 18n;
242+
243+
const mintTx = await token.write.mint([privateKey.address, lockAmount + voteAmount], { account: privateKey });
244+
await publicClient.waitForTransactionReceipt({ hash: mintTx });
245+
logger.info(`Minted tokens`);
246+
247+
const approveTx = await token.write.approve([addresses.governanceAddress.toString(), lockAmount + voteAmount], {
248+
account: privateKey,
249+
});
250+
await publicClient.waitForTransactionReceipt({ hash: approveTx });
251+
logger.info(`Approved tokens`);
252+
253+
const depositTx = await governance.write.deposit([privateKey.address, lockAmount + voteAmount], {
254+
account: privateKey,
255+
});
256+
await publicClient.waitForTransactionReceipt({ hash: depositTx });
257+
logger.info(`Deposited tokens`);
258+
259+
await governance.write.proposeWithLock([payloadAddress, privateKey.address], {
260+
account: privateKey,
261+
});
262+
263+
return { governance, voteAmount };
264+
}

0 commit comments

Comments
 (0)