diff --git a/docs/docs/developers/reference/smart_contract_reference/portals/data_structures.md b/docs/docs/developers/reference/smart_contract_reference/portals/data_structures.md index 57c16ca33679..f1f63575e873 100644 --- a/docs/docs/developers/reference/smart_contract_reference/portals/data_structures.md +++ b/docs/docs/developers/reference/smart_contract_reference/portals/data_structures.md @@ -54,17 +54,4 @@ A message that is sent from L2 to L1. | `recipient` | `L1Actor` | The actor on L1 that is to receive the message. | | `content` | `field (~254 bits)` | The field element containing the content to be consumed by the portal on L1. | -## `RegistrySnapshot` - -A snapshot of the registry values. - -#include_code registry_snapshot l1-contracts/src/governance/libraries/DataStructures.sol solidity - -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `rollup` | `address` | The address of the rollup contract for the snapshot. | -| `blockNumber` | `uint256` | The block number at which the snapshot was created. | - - - diff --git a/docs/docs/developers/reference/smart_contract_reference/portals/registry.md b/docs/docs/developers/reference/smart_contract_reference/portals/registry.md index 1a129fe83c71..317607c502f3 100644 --- a/docs/docs/developers/reference/smart_contract_reference/portals/registry.md +++ b/docs/docs/developers/reference/smart_contract_reference/portals/registry.md @@ -13,55 +13,26 @@ Retrieves the number of versions that have been deployed. #include_code registry_number_of_versions l1-contracts/src/governance/interfaces/IRegistry.sol solidity -| Name | Description | -| -------------- | ----------- | -| ReturnValue | The number of versions that have been deployed | +| Name | Description | +| ----------- | ---------------------------------------------- | +| ReturnValue | The number of versions that have been deployed | -## `getRollup()` -Retrieves the current rollup contract. - -#include_code registry_get_rollup l1-contracts/src/governance/interfaces/IRegistry.sol solidity - -| Name | Description | -| -------------- | ----------- | -| ReturnValue | The current rollup | - -## `getVersionFor(address _rollup)` - -Retrieve the version of a specific rollup contract. - -#include_code registry_get_version_for l1-contracts/src/governance/interfaces/IRegistry.sol solidity +## `getCanonicalRollup()` -| Name | Description | -| -------------- | ----------- | -| `_rollup` | The address of the rollup to lookup | -| ReturnValue | The version number of `_rollup` | - -#### Edge cases -Will revert with `Registry__RollupNotRegistered(_rollup)` if the rollup have not been registered. - -## `getSnapshot(uint256 _version)` - -Retrieve the snapshot of a specific version. - -#include_code registry_snapshot l1-contracts/src/governance/libraries/DataStructures.sol solidity -#include_code registry_get_snapshot l1-contracts/src/governance/interfaces/IRegistry.sol solidity - -| Name | Description | -| -------------- | ----------- | -| `_version` | The version number to fetch data for | -| ReturnValue.rollup | The address of the `rollup` for the `_version` | -| ReturnValue.blockNumber | The block number of the snapshot creation | +Retrieves the current rollup contract. +#include_code registry_get_canonical_rollup l1-contracts/src/governance/interfaces/IRegistry.sol solidity -## `getCurrentSnapshot()` +| Name | Description | +| ----------- | ------------------ | +| ReturnValue | The current rollup | -Retrieves the snapshot for the current version. +## `getRollup(uint256 _version)` -#include_code registry_get_current_snapshot l1-contracts/src/governance/interfaces/IRegistry.sol solidity +Retrieves the rollup contract for a specfic version. -| Name | Description | -| -------------- | ----------- | -| ReturnValue.rollup | The address of the `rollup` for the current `_version` | -| ReturnValue.blockNumber | The block number of the snapshot creation | +#include_code registry_get_rollup l1-contracts/src/governance/interfaces/IRegistry.sol solidity +| Name | Description | +| ----------- | ------------------ | +| ReturnValue | The current rollup | diff --git a/l1-contracts/gas_benchmark.md b/l1-contracts/gas_benchmark.md index 0927d04aa497..9245c4e52f78 100644 --- a/l1-contracts/gas_benchmark.md +++ b/l1-contracts/gas_benchmark.md @@ -1,9 +1,9 @@ | src/core/Rollup.sol:Rollup contract | | | | | | |-------------------------------------|-----------------|----------|----------|----------|---------| | Deployment Cost | Deployment Size | | | | | -| 7944840 | 38653 | | | | | +| 8451525 | 41441 | | | | | | Function Name | min | avg | median | max | # calls | -| cheat__InitialiseValidatorSet | 13524835 | 13524835 | 13524835 | 13524835 | 1 | +| cheat__InitialiseValidatorSet | 13526635 | 13526635 | 13526635 | 13526635 | 1 | | getBlock | 1230 | 1230 | 1230 | 1230 | 12 | | getBurnAddress | 369 | 369 | 369 | 369 | 1 | | getCurrentEpoch | 1017 | 1017 | 1017 | 1017 | 397 | @@ -11,16 +11,18 @@ | getCurrentSlot | 823 | 833 | 823 | 4823 | 397 | | getEpochCommittee | 135768 | 139483 | 135780 | 259358 | 100 | | getEpochForBlock | 1016 | 1016 | 1016 | 1016 | 196 | +| getFeeAssetPortal | 519 | 519 | 519 | 519 | 1 | | getFeeHeader | 1457 | 1457 | 1457 | 1457 | 95 | -| getManaBaseFeeAt | 20442 | 26863 | 27182 | 34313 | 195 | +| getManaBaseFeeAt | 19460 | 25848 | 26200 | 26831 | 195 | | getPendingBlockNumber | 507 | 511 | 507 | 2507 | 401 | | getProvenBlockNumber | 490 | 490 | 490 | 490 | 3 | | getTimestampForSlot | 887 | 887 | 887 | 887 | 195 | +| getVersion | 493 | 513 | 493 | 2493 | 100 | | setProvingCostPerMana | 25915 | 25942 | 25915 | 28715 | 101 | -| submitEpochRootProof | 771062 | 783900 | 771086 | 809552 | 3 | +| submitEpochRootProof | 778549 | 791392 | 778573 | 817054 | 3 | | src/periphery/Forwarder.sol:Forwarder contract | | | | | | |------------------------------------------------|-----------------|--------|--------|---------|---------| | Deployment Cost | Deployment Size | | | | | | 358690 | 1553 | | | | | | Function Name | min | avg | median | max | # calls | -| forward | 634788 | 685012 | 645781 | 1916159 | 100 | +| forward | 627336 | 677587 | 638357 | 1908717 | 100 | diff --git a/l1-contracts/gas_report.md b/l1-contracts/gas_report.md index 8d5d1a4ef5d4..e0a9839acc88 100644 --- a/l1-contracts/gas_report.md +++ b/l1-contracts/gas_report.md @@ -1,94 +1,97 @@ -| src/core/FeeJuicePortal.sol:FeeJuicePortal contract | | | | | | -|-----------------------------------------------------|-----------------|--------|--------|--------|---------| -| Deployment Cost | Deployment Size | | | | | -| 589795 | 2886 | | | | | -| Function Name | min | avg | median | max | # calls | -| L2_TOKEN_ADDRESS | 194 | 194 | 194 | 194 | 256 | -| UNDERLYING | 270 | 270 | 270 | 270 | 3080 | -| canonicalRollup | 1016 | 3632 | 5516 | 5516 | 5574 | -| depositToAztecPublic | 42812 | 127386 | 128025 | 128025 | 258 | -| distributeFees | 27333 | 56798 | 57006 | 57006 | 258 | -| initialize | 49029 | 49029 | 49029 | 49029 | 1566 | +| src/core/FeeJuicePortal.sol:FeeJuicePortal contract | | | | | | +|-----------------------------------------------------|-----------------|-------|--------|--------|---------| +| Deployment Cost | Deployment Size | | | | | +| 0 | 0 | | | | | +| Function Name | min | avg | median | max | # calls | +| L2_TOKEN_ADDRESS | 239 | 239 | 239 | 239 | 1 | +| depositToAztecPublic | 28903 | 59187 | 34503 | 114156 | 3 | +| distributeFees | 22005 | 33846 | 27856 | 51678 | 3 | +| initialize | 48985 | 48985 | 48985 | 48985 | 1566 | | src/core/Rollup.sol:Rollup contract | | | | | | |-------------------------------------|-----------------|---------|---------|----------|---------| | Deployment Cost | Deployment Size | | | | | -| 7925568 | 38750 | | | | | +| 8451525 | 41441 | | | | | | Function Name | min | avg | median | max | # calls | -| archive | 605 | 605 | 605 | 605 | 2475 | -| cheat__InitialiseValidatorSet | 752109 | 7052330 | 752133 | 13524799 | 519 | -| claimProverRewards | 31794 | 53315 | 34239 | 93914 | 3 | -| claimSequencerRewards | 57174 | 57174 | 57174 | 57174 | 1 | -| deposit | 169778 | 329145 | 342652 | 342652 | 256 | -| getAttesters | 1970 | 26343 | 26629 | 26629 | 259 | -| getBlock | 1230 | 1230 | 1230 | 1230 | 910 | +| archive | 605 | 605 | 605 | 605 | 2474 | +| cheat__InitialiseValidatorSet | 752181 | 4982899 | 752205 | 13526635 | 776 | +| claimProverRewards | 31800 | 53321 | 34245 | 93920 | 3 | +| claimSequencerRewards | 57180 | 57180 | 57180 | 57180 | 1 | +| deposit | 169796 | 326462 | 342670 | 342670 | 256 | +| getAttesters | 1971 | 14228 | 1971 | 26630 | 515 | +| getBlock | 1230 | 1230 | 1230 | 1230 | 883 | +| getBurnAddress | 369 | 369 | 369 | 369 | 1 | | getCollectiveProverRewardsForEpoch | 636 | 1636 | 1636 | 2636 | 4 | -| getCurrentEpoch | 1017 | 1017 | 1017 | 1017 | 1032 | +| getCurrentEpoch | 1017 | 1017 | 1017 | 1017 | 1941 | | getCurrentEpochCommittee | 42004 | 42004 | 42004 | 42004 | 1 | -| getCurrentProposer | 44246 | 117406 | 52217 | 263958 | 795 | -| getCurrentSlot | 823 | 1442 | 823 | 4823 | 142 | -| getEpochCommittee | 2010 | 14068 | 14218 | 14218 | 520 | -| getEpochDuration | 439 | 439 | 439 | 439 | 256 | +| getCurrentProposer | 44246 | 122673 | 52218 | 263958 | 995 | +| getCurrentSlot | 823 | 993 | 823 | 4823 | 539 | +| getEpochCommittee | 35560 | 91622 | 135780 | 259358 | 1130 | +| getEpochDuration | 439 | 439 | 439 | 439 | 512 | +| getEpochForBlock | 1016 | 1016 | 1016 | 1016 | 196 | | getFeeAssetPerEth | 1440 | 1440 | 1440 | 1440 | 1 | -| getHasSubmitted | 942 | 1192 | 942 | 2942 | 8 | -| getInbox | 476 | 581 | 476 | 2476 | 4926 | -| getInfo | 1527 | 1527 | 1527 | 1527 | 16 | -| getManaBaseFeeAt | 7834 | 15737 | 16504 | 16514 | 2333 | -| getOutbox | 496 | 873 | 496 | 2496 | 5434 | -| getPendingBlockNumber | 507 | 507 | 507 | 507 | 1546 | +| getFeeAssetPortal | 519 | 519 | 519 | 519 | 1567 | +| getFeeHeader | 1457 | 1457 | 1457 | 1457 | 95 | +| getHasSubmitted | 943 | 1193 | 943 | 2943 | 8 | +| getInbox | 476 | 477 | 476 | 2476 | 7004 | +| getInfo | 1533 | 1533 | 1533 | 1533 | 16 | +| getManaBaseFeeAt | 6161 | 14959 | 14831 | 26831 | 2791 | +| getOutbox | 496 | 498 | 496 | 2496 | 4670 | +| getPendingBlockNumber | 507 | 508 | 507 | 2507 | 1947 | | getProofSubmissionWindow | 404 | 404 | 404 | 404 | 4 | -| getProvenBlockNumber | 490 | 762 | 490 | 2490 | 7553 | +| getProvenBlockNumber | 490 | 762 | 490 | 2490 | 7554 | | getProvingCostPerManaInEth | 429 | 429 | 429 | 429 | 1 | | getProvingCostPerManaInFeeAsset | 4164 | 4164 | 4164 | 4164 | 1 | -| getSequencerRewards | 671 | 1071 | 671 | 2671 | 5 | -| getSlasher | 496 | 496 | 496 | 496 | 518 | -| getSlotDuration | 421 | 421 | 421 | 421 | 256 | -| getSpecificProverRewardsForEpoch | 822 | 2130 | 1634 | 3634 | 5 | -| getTargetCommitteeSize | 462 | 462 | 462 | 462 | 768 | -| getTimestampForSlot | 887 | 888 | 887 | 4887 | 2462 | -| propose | 129177 | 362402 | 363530 | 572838 | 2601 | +| getSequencerRewards | 677 | 1077 | 677 | 2677 | 5 | +| getSlasher | 496 | 496 | 496 | 496 | 774 | +| getSlotDuration | 421 | 421 | 421 | 421 | 512 | +| getSpecificProverRewardsForEpoch | 823 | 2131 | 1635 | 3635 | 5 | +| getTargetCommitteeSize | 462 | 462 | 462 | 462 | 1024 | +| getTimestampForSlot | 887 | 888 | 887 | 4887 | 2657 | +| getVersion | 493 | 1023 | 493 | 2493 | 7900 | +| propose | 139414 | 354778 | 352912 | 601007 | 2601 | | prune | 25731 | 36205 | 37466 | 41951 | 6 | -| setProvingCostPerMana | 28691 | 28691 | 28691 | 28691 | 2 | +| setProvingCostPerMana | 25915 | 25996 | 25915 | 28715 | 103 | | setupEpoch | 208152 | 1372793 | 1400090 | 1400090 | 262 | -| submitEpochRootProof | 64866 | 421805 | 420725 | 448480 | 909 | +| submitEpochRootProof | 64859 | 420435 | 418029 | 817054 | 873 | | src/core/messagebridge/Inbox.sol:Inbox contract | | | | | | |-------------------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | | 0 | 0 | | | | | | Function Name | min | avg | median | max | # calls | -| getRoot | 802 | 802 | 802 | 802 | 2 | -| inProgress | 304 | 304 | 304 | 304 | 3 | -| sendL2Message | 44403 | 54747 | 47796 | 95703 | 41504 | -| totalMessagesInserted | 284 | 284 | 284 | 284 | 512 | +| getRoot | 754 | 2158 | 2754 | 2754 | 2596 | +| inProgress | 282 | 282 | 282 | 282 | 3 | +| sendL2Message | 44484 | 54828 | 47877 | 95784 | 41504 | +| totalMessagesInserted | 284 | 1284 | 1284 | 2284 | 2 | | src/core/messagebridge/Outbox.sol:Outbox contract | | | | | | |---------------------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 586673 | 2646 | | | | | +| 618184 | 2855 | | | | | | Function Name | min | avg | median | max | # calls | -| consume | 28894 | 72144 | 73138 | 73400 | 4707 | -| getRootData | 940 | 1343 | 1149 | 3217 | 2733 | +| consume | 28894 | 72054 | 73183 | 73445 | 4109 | +| getRootData | 940 | 1343 | 1149 | 3217 | 2732 | | hasMessageBeenConsumedAtBlockAndIndex | 591 | 2583 | 2591 | 2591 | 259 | -| insert | 22188 | 57527 | 68264 | 68264 | 1099 | +| insert | 22188 | 57505 | 68252 | 68264 | 1097 | | src/core/staking/Slasher.sol:Slasher contract | | | | | | |-----------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | | 0 | 0 | | | | | | Function Name | min | avg | median | max | # calls | | PROPOSER | 182 | 182 | 182 | 182 | 2 | -| slash | 125484 | 125484 | 125484 | 125484 | 1 | +| slash | 124034 | 124034 | 124034 | 124034 | 1 | | src/core/staking/SlashingProposer.sol:SlashingProposer contract | | | | | | |-----------------------------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | | 0 | 0 | | | | | | Function Name | min | avg | median | max | # calls | -| executeProposal | 140075 | 140075 | 140075 | 140075 | 1 | +| executeProposal | 138625 | 138625 | 138625 | 138625 | 1 | | vote | 64017 | 75384 | 64017 | 120852 | 10 | | src/governance/CoinIssuer.sol:CoinIssuer contract | | | | | | |---------------------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 326385 | 1465 | | | | | +| 326433 | 1465 | | | | | | Function Name | min | avg | median | max | # calls | | RATE | 239 | 239 | 239 | 239 | 768 | -| mint | 23901 | 43850 | 26637 | 81131 | 768 | +| mint | 23901 | 43849 | 26631 | 81131 | 768 | | mintAvailable | 503 | 503 | 503 | 503 | 1283 | | timeOfLastMint | 360 | 360 | 360 | 360 | 256 | | src/governance/Governance.sol:Governance contract | | | | | | @@ -96,69 +99,65 @@ | Deployment Cost | Deployment Size | | | | | | 2332350 | 10841 | | | | | | Function Name | min | avg | median | max | # calls | -| deposit | 27965 | 171786 | 186596 | 188519 | 9729 | +| deposit | 27965 | 171787 | 186596 | 188519 | 9729 | | dropProposal | 23739 | 40533 | 33600 | 63600 | 2307 | -| execute | 26209 | 71295 | 71327 | 161717 | 3076 | -| finaliseWithdraw | 23757 | 45077 | 48283 | 65383 | 6057 | +| execute | 26209 | 70507 | 71327 | 152243 | 3076 | +| finaliseWithdraw | 23757 | 45261 | 48283 | 65383 | 6017 | | getConfiguration | 1913 | 12163 | 19913 | 19913 | 5396 | | getProposal | 3523 | 8023 | 3523 | 31523 | 10590 | | getProposalState | 469 | 11470 | 13558 | 21242 | 23311 | -| getWithdrawal | 1075 | 1075 | 1075 | 1075 | 10010 | +| getWithdrawal | 1075 | 1075 | 1075 | 1075 | 10166 | | governanceProposer | 424 | 1418 | 424 | 2424 | 515 | -| initiateWithdraw | 30945 | 199027 | 211342 | 228958 | 7499 | +| initiateWithdraw | 30945 | 199174 | 211342 | 228958 | 7573 | | powerAt | 1042 | 1412 | 1042 | 3029 | 4608 | | proposalCount | 338 | 1714 | 2338 | 2338 | 1116 | -| propose | 23763 | 321927 | 320487 | 337587 | 606 | -| proposeWithLock | 26545 | 421003 | 422627 | 422627 | 257 | -| totalPowerAt | 612 | 1569 | 883 | 3568 | 6067 | +| propose | 23763 | 321926 | 320487 | 337587 | 606 | +| proposeWithLock | 26545 | 421004 | 422627 | 422627 | 257 | +| totalPowerAt | 612 | 1566 | 883 | 3568 | 6093 | | updateConfiguration | 23457 | 32910 | 24180 | 48186 | 6145 | -| updateGovernanceProposer | 21693 | 27184 | 28016 | 28028 | 2048 | +| updateGovernanceProposer | 21705 | 27183 | 28016 | 28028 | 2048 | | vote | 30670 | 87818 | 94478 | 94500 | 12289 | -| withdrawalCount | 383 | 391 | 383 | 2383 | 2482 | -| src/governance/Registry.sol:Registry contract | | | | | | -|-----------------------------------------------|-----------------|--------|--------|--------|---------| -| Deployment Cost | Deployment Size | | | | | -| 500615 | 2063 | | | | | -| Function Name | min | avg | median | max | # calls | -| getCurrentSnapshot | 664 | 2664 | 2664 | 4664 | 514 | -| getGovernance | 341 | 2159 | 2341 | 2341 | 2829 | -| getRollup | 374 | 2358 | 2374 | 2374 | 869977 | -| getSnapshot | 4740 | 4740 | 4740 | 4740 | 257 | -| getVersionFor | 743 | 3527 | 2927 | 4927 | 773 | -| isRollupRegistered | 657 | 3805 | 2812 | 4812 | 515 | -| numberOfVersions | 350 | 1685 | 2350 | 2350 | 770 | -| transferOwnership | 28592 | 28592 | 28592 | 28592 | 106 | -| upgrade | 23672 | 103312 | 106801 | 106801 | 6176 | +| withdrawalCount | 383 | 391 | 383 | 2383 | 2508 | +| src/governance/Registry.sol:Registry contract | | | | | | +|-----------------------------------------------|-----------------|-------|--------|-------|---------| +| Deployment Cost | Deployment Size | | | | | +| 845410 | 4070 | | | | | +| Function Name | min | avg | median | max | # calls | +| addRollup | 23721 | 90721 | 95470 | 97461 | 4151 | +| getCanonicalRollup | 1016 | 6998 | 7016 | 7016 | 865880 | +| getGovernance | 309 | 2142 | 2309 | 2309 | 3086 | +| getRewardDistributor | 267 | 267 | 267 | 267 | 2347 | +| getRollup | 592 | 592 | 592 | 592 | 1 | +| numberOfVersions | 325 | 325 | 325 | 325 | 1 | +| transferOwnership | 28665 | 28665 | 28665 | 28665 | 106 | +| updateGovernance | 47218 | 47218 | 47218 | 47218 | 19 | | src/governance/RewardDistributor.sol:RewardDistributor contract | | | | | | |-----------------------------------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 513664 | 2360 | | | | | +| 475915 | 2290 | | | | | | Function Name | min | avg | median | max | # calls | -| BLOCK_REWARD | 238 | 238 | 238 | 238 | 376 | -| canonicalRollup | 1143 | 3143 | 3143 | 5643 | 904 | -| claim | 30122 | 45856 | 35665 | 64090 | 513 | -| owner | 2384 | 2384 | 2384 | 2384 | 257 | -| registry | 347 | 1347 | 1347 | 2347 | 2 | -| updateRegistry | 23757 | 23781 | 23757 | 30119 | 257 | +| BLOCK_REWARD | 238 | 238 | 238 | 238 | 381 | +| canonicalRollup | 10158 | 10158 | 10158 | 10158 | 863 | +| claim | 33152 | 49042 | 38911 | 67336 | 513 | | src/governance/proposer/GovernanceProposer.sol:GovernanceProposer contract | | | | | | |----------------------------------------------------------------------------|-----------------|-------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 639733 | 3152 | | | | | +| 639721 | 3152 | | | | | | Function Name | min | avg | median | max | # calls | | LIFETIME_IN_ROUNDS | 216 | 216 | 216 | 216 | 512 | | M | 261 | 261 | 261 | 261 | 4868 | | N | 260 | 260 | 260 | 260 | 1949 | | REGISTRY | 205 | 205 | 205 | 205 | 256 | | computeRound | 435 | 435 | 435 | 435 | 266 | -| executeProposal | 29491 | 43507 | 37213 | 366485 | 2053 | +| executeProposal | 34133 | 48109 | 41822 | 371095 | 2053 | | getExecutor | 3397 | 3397 | 3397 | 3397 | 256 | | getInstance | 951 | 951 | 951 | 951 | 256 | | rounds | 865 | 865 | 865 | 865 | 522 | -| vote | 29794 | 50139 | 50074 | 126085 | 855787 | +| vote | 34436 | 54804 | 54739 | 130727 | 859435 | | yeaCount | 851 | 851 | 851 | 851 | 16 | -| src/periphery/Forwarder.sol:Forwarder contract | | | | | | -|------------------------------------------------|-----------------|-------|--------|--------|---------| -| Deployment Cost | Deployment Size | | | | | -| 358690 | 1553 | | | | | -| Function Name | min | avg | median | max | # calls | -| forward | 24936 | 27197 | 27012 | 132983 | 514 | +| src/periphery/Forwarder.sol:Forwarder contract | | | | | | +|------------------------------------------------|-----------------|--------|--------|---------|---------| +| Deployment Cost | Deployment Size | | | | | +| 358690 | 1553 | | | | | +| Function Name | min | avg | median | max | # calls | +| forward | 24936 | 133124 | 28924 | 1908717 | 614 | diff --git a/l1-contracts/src/core/FeeJuicePortal.sol b/l1-contracts/src/core/FeeJuicePortal.sol index e619f54d792e..288d8ded461a 100644 --- a/l1-contracts/src/core/FeeJuicePortal.sol +++ b/l1-contracts/src/core/FeeJuicePortal.sol @@ -9,28 +9,26 @@ import {Constants} from "@aztec/core/libraries/ConstantsGen.sol"; import {Hash} from "@aztec/core/libraries/crypto/Hash.sol"; import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; -import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol"; contract FeeJuicePortal is IFeeJuicePortal { using SafeERC20 for IERC20; - IRegistry public immutable REGISTRY; + bytes32 public constant L2_TOKEN_ADDRESS = bytes32(Constants.FEE_JUICE_ADDRESS); + + IRollup public immutable ROLLUP; + IInbox public immutable INBOX; IERC20 public immutable UNDERLYING; - bytes32 public immutable L2_TOKEN_ADDRESS; + uint256 public immutable VERSION; bool public initialized; - constructor(address _registry, address _underlying, bytes32 _l2TokenAddress) { - require( - _registry != address(0) && _underlying != address(0) && _l2TokenAddress != 0, - Errors.FeeJuicePortal__InvalidInitialization() - ); - - REGISTRY = IRegistry(_registry); - UNDERLYING = IERC20(_underlying); - L2_TOKEN_ADDRESS = _l2TokenAddress; + constructor(IRollup _rollup, IERC20 _underlying, IInbox _inbox, uint256 _version) { + ROLLUP = _rollup; + INBOX = _inbox; + UNDERLYING = _underlying; + VERSION = _version; } /** @@ -66,10 +64,7 @@ contract FeeJuicePortal is IFeeJuicePortal { returns (bytes32, uint256) { // Preamble - address rollup = canonicalRollup(); - uint256 version = REGISTRY.getVersionFor(rollup); - IInbox inbox = IRollup(rollup).getInbox(); - DataStructures.L2Actor memory actor = DataStructures.L2Actor(L2_TOKEN_ADDRESS, version); + DataStructures.L2Actor memory actor = DataStructures.L2Actor(L2_TOKEN_ADDRESS, VERSION); // Hash the message content to be reconstructed in the receiving contract bytes32 contentHash = @@ -79,7 +74,7 @@ contract FeeJuicePortal is IFeeJuicePortal { UNDERLYING.safeTransferFrom(msg.sender, address(this), _amount); // Send message to rollup - (bytes32 key, uint256 index) = inbox.sendL2Message(actor, contentHash, _secretHash); + (bytes32 key, uint256 index) = INBOX.sendL2Message(actor, contentHash, _secretHash); emit DepositToAztecPublic(_to, _amount, _secretHash, key, index); @@ -97,13 +92,9 @@ contract FeeJuicePortal is IFeeJuicePortal { * @param _amount - The amount to pay them */ function distributeFees(address _to, uint256 _amount) external override(IFeeJuicePortal) { - require(msg.sender == canonicalRollup(), Errors.FeeJuicePortal__Unauthorized()); + require(msg.sender == address(ROLLUP), Errors.FeeJuicePortal__Unauthorized()); UNDERLYING.safeTransfer(_to, _amount); emit FeesDistributed(_to, _amount); } - - function canonicalRollup() public view override(IFeeJuicePortal) returns (address) { - return REGISTRY.getRollup(); - } } diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 19ac02f22c52..647d98ae5e75 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -67,22 +67,13 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore { using PriceLib for EthValue; constructor( - IFeeJuicePortal _fpcJuicePortal, + IERC20 _feeAsset, IRewardDistributor _rewardDistributor, IERC20 _stakingAsset, address _governance, GenesisState memory _genesisState, RollupConfigInput memory _config - ) - RollupCore( - _fpcJuicePortal, - _rewardDistributor, - _stakingAsset, - _governance, - _genesisState, - _config - ) - {} + ) RollupCore(_feeAsset, _rewardDistributor, _stakingAsset, _governance, _genesisState, _config) {} /** * @notice Validate a header for submission diff --git a/l1-contracts/src/core/RollupCore.sol b/l1-contracts/src/core/RollupCore.sol index 36f5cf25cd99..6a5172538728 100644 --- a/l1-contracts/src/core/RollupCore.sol +++ b/l1-contracts/src/core/RollupCore.sol @@ -2,8 +2,10 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.27; +import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol"; import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol"; import { + IRollup, IRollupCore, ITestRollup, CheatDepositArgs, @@ -65,7 +67,7 @@ contract RollupCore is bool public checkBlob = true; constructor( - IFeeJuicePortal _fpcJuicePortal, + IERC20 _feeAsset, IRewardDistributor _rewardDistributor, IERC20 _stakingAsset, address _governance, @@ -85,14 +87,24 @@ contract RollupCore is RollupStore storage rollupStore = STFLib.getStorage(); rollupStore.config.proofSubmissionWindow = _config.aztecProofSubmissionWindow; - rollupStore.config.feeAsset = _fpcJuicePortal.UNDERLYING(); - rollupStore.config.feeAssetPortal = _fpcJuicePortal; + rollupStore.config.feeAsset = _feeAsset; rollupStore.config.rewardDistributor = _rewardDistributor; rollupStore.config.epochProofVerifier = new MockVerifier(); - rollupStore.config.version = 1; + // @todo handle case where L1 forks and chainid is different + // @note Truncated to 32 bits to make simpler to deal with all the node changes at a separate time. + uint256 version = uint32( + uint256( + keccak256(abi.encode(bytes("aztec_rollup"), block.chainid, address(this), _genesisState)) + ) + ); + rollupStore.config.version = version; rollupStore.config.inbox = - IInbox(address(new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT))); - rollupStore.config.outbox = IOutbox(address(new Outbox(address(this)))); + IInbox(address(new Inbox(address(this), version, Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT))); + rollupStore.config.outbox = IOutbox(address(new Outbox(address(this), version))); + + rollupStore.config.feeAssetPortal = IFeeJuicePortal( + new FeeJuicePortal(IRollup(address(this)), _feeAsset, rollupStore.config.inbox, version) + ); FeeLib.initialize(_config.manaTarget, _config.provingCostPerMana); } diff --git a/l1-contracts/src/core/interfaces/IFeeJuicePortal.sol b/l1-contracts/src/core/interfaces/IFeeJuicePortal.sol index 1bec19f41958..b50108c2df29 100644 --- a/l1-contracts/src/core/interfaces/IFeeJuicePortal.sol +++ b/l1-contracts/src/core/interfaces/IFeeJuicePortal.sol @@ -2,8 +2,9 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.27; -import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; +import {IInbox} from "./messagebridge/IInbox.sol"; interface IFeeJuicePortal { event DepositToAztecPublic( @@ -16,12 +17,15 @@ interface IFeeJuicePortal { function depositToAztecPublic(bytes32 _to, uint256 _amount, bytes32 _secretHash) external returns (bytes32, uint256); - function canonicalRollup() external view returns (address); // solhint-disable-next-line func-name-mixedcase function UNDERLYING() external view returns (IERC20); // solhint-disable-next-line func-name-mixedcase function L2_TOKEN_ADDRESS() external view returns (bytes32); // solhint-disable-next-line func-name-mixedcase - function REGISTRY() external view returns (IRegistry); + function VERSION() external view returns (uint256); + // solhint-disable-next-line func-name-mixedcase + function INBOX() external view returns (IInbox); + // solhint-disable-next-line func-name-mixedcase + function ROLLUP() external view returns (IRollup); } diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index e4f693ba2d4b..fe8e44944930 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -21,6 +21,7 @@ library Errors { // Inbox error Inbox__Unauthorized(); // 0xe5336a6b error Inbox__ActorTooLarge(bytes32 actor); // 0xa776a06e + error Inbox__VersionMismatch(uint256 expected, uint256 actual); // 0x47452014 error Inbox__ContentTooLarge(bytes32 content); // 0x47452014 error Inbox__SecretHashTooLarge(bytes32 secretHash); // 0xecde7e2c error Inbox__MustBuildBeforeConsume(); // 0xc4901999 @@ -28,7 +29,7 @@ library Errors { // Outbox error Outbox__Unauthorized(); // 0x2c9490c2 error Outbox__InvalidChainId(); // 0x577ec7c4 - error Outbox__InvalidVersion(uint256 entry, uint256 message); // 0x7915cac3 + error Outbox__VersionMismatch(uint256 expected, uint256 actual); error Outbox__NothingToConsume(bytes32 messageHash); // 0xfb4fb506 error Outbox__IncompatibleEntryArguments( bytes32 messageHash, diff --git a/l1-contracts/src/core/libraries/rollup/EpochProofLib.sol b/l1-contracts/src/core/libraries/rollup/EpochProofLib.sol index 9b005d6b6e2c..1f0491517622 100644 --- a/l1-contracts/src/core/libraries/rollup/EpochProofLib.sol +++ b/l1-contracts/src/core/libraries/rollup/EpochProofLib.sol @@ -278,74 +278,70 @@ library EpochProofLib { function handleRewardsAndFees(SubmitEpochRootProofArgs memory _args, Epoch _endEpoch) private { RollupStore storage rollupStore = STFLib.getStorage(); - bool isFeeCanonical = address(this) == rollupStore.config.feeAssetPortal.canonicalRollup(); bool isRewardDistributorCanonical = address(this) == rollupStore.config.rewardDistributor.canonicalRollup(); - if (isFeeCanonical || isRewardDistributorCanonical) { - uint256 length = _args.end - _args.start + 1; - EpochRewards storage $er = rollupStore.epochRewards[_endEpoch]; - SubEpochRewards storage $sr = $er.subEpoch[length]; + uint256 length = _args.end - _args.start + 1; + EpochRewards storage $er = rollupStore.epochRewards[_endEpoch]; + SubEpochRewards storage $sr = $er.subEpoch[length]; - { - address prover = _args.args.proverId; - require( - !$sr.hasSubmitted[prover], Errors.Rollup__ProverHaveAlreadySubmitted(prover, _endEpoch) - ); - $sr.hasSubmitted[prover] = true; - } - $sr.summedCount += 1; + { + address prover = _args.args.proverId; + require( + !$sr.hasSubmitted[prover], Errors.Rollup__ProverHaveAlreadySubmitted(prover, _endEpoch) + ); + $sr.hasSubmitted[prover] = true; + } + $sr.summedCount += 1; - if (length > $er.longestProvenLength) { - Values memory v; - Totals memory t; + if (length > $er.longestProvenLength) { + Values memory v; + Totals memory t; - { - uint256 added = length - $er.longestProvenLength; - uint256 blockRewardsAvailable = isRewardDistributorCanonical - ? rollupStore.config.rewardDistributor.claimBlockRewards(address(this), added) - : 0; - uint256 sequencerShare = blockRewardsAvailable / 2; - v.sequencerBlockReward = sequencerShare / added; - - $er.rewards += (blockRewardsAvailable - sequencerShare); - } + { + uint256 added = length - $er.longestProvenLength; + uint256 blockRewardsAvailable = isRewardDistributorCanonical + ? rollupStore.config.rewardDistributor.claimBlockRewards(address(this), added) + : 0; + uint256 sequencerShare = blockRewardsAvailable / 2; + v.sequencerBlockReward = sequencerShare / added; + + $er.rewards += (blockRewardsAvailable - sequencerShare); + } - FeeStore storage feeStore = FeeLib.getStorage(); + FeeStore storage feeStore = FeeLib.getStorage(); - for (uint256 i = $er.longestProvenLength; i < length; i++) { - CompressedFeeHeader storage feeHeader = feeStore.feeHeaders[_args.start + i]; + for (uint256 i = $er.longestProvenLength; i < length; i++) { + CompressedFeeHeader storage feeHeader = feeStore.feeHeaders[_args.start + i]; - v.manaUsed = feeHeader.getManaUsed(); + v.manaUsed = feeHeader.getManaUsed(); - (uint256 fee, uint256 burn) = isFeeCanonical - ? (uint256(_args.fees[1 + i * 2]), feeHeader.getCongestionCost() * v.manaUsed) - : (0, 0); + uint256 fee = uint256(_args.fees[1 + i * 2]); + uint256 burn = feeHeader.getCongestionCost() * v.manaUsed; - t.feesToClaim += fee; - t.totalBurn += burn; + t.feesToClaim += fee; + t.totalBurn += burn; - // Compute the proving fee in the fee asset - v.proverFee = Math.min(v.manaUsed * feeHeader.getProvingCost(), fee - burn); - $er.rewards += v.proverFee; + // Compute the proving fee in the fee asset + v.proverFee = Math.min(v.manaUsed * feeHeader.getProvingCost(), fee - burn); + $er.rewards += v.proverFee; - v.sequencerFee = fee - burn - v.proverFee; + v.sequencerFee = fee - burn - v.proverFee; - { - v.sequencer = fieldToAddress(_args.fees[i * 2]); - rollupStore.sequencerRewards[v.sequencer] += (v.sequencerBlockReward + v.sequencerFee); - } + { + v.sequencer = fieldToAddress(_args.fees[i * 2]); + rollupStore.sequencerRewards[v.sequencer] += (v.sequencerBlockReward + v.sequencerFee); } + } - $er.longestProvenLength = length; + $er.longestProvenLength = length; - if (t.feesToClaim > 0) { - rollupStore.config.feeAssetPortal.distributeFees(address(this), t.feesToClaim); - } + if (t.feesToClaim > 0) { + rollupStore.config.feeAssetPortal.distributeFees(address(this), t.feesToClaim); + } - if (t.totalBurn > 0) { - rollupStore.config.feeAsset.transfer(BURN_ADDRESS, t.totalBurn); - } + if (t.totalBurn > 0) { + rollupStore.config.feeAsset.transfer(BURN_ADDRESS, t.totalBurn); } } } diff --git a/l1-contracts/src/core/libraries/rollup/ProposeLib.sol b/l1-contracts/src/core/libraries/rollup/ProposeLib.sol index 00db58ceccdf..e3feb399589a 100644 --- a/l1-contracts/src/core/libraries/rollup/ProposeLib.sol +++ b/l1-contracts/src/core/libraries/rollup/ProposeLib.sol @@ -229,23 +229,7 @@ library ProposeLib { view returns (ManaBaseFeeComponents memory) { - RollupStore storage rollupStore = STFLib.getStorage(); - - // If we are not the canonical rollup, we cannot claim any fees, so we return 0s - // The congestion multiplier could be computed, but as it could only be used to guide - // might as well save the gas and anyone interested can do it off-chain. - if (address(this) != rollupStore.config.feeAssetPortal.canonicalRollup()) { - return ManaBaseFeeComponents({ - congestionCost: 0, - provingCost: 0, - congestionMultiplier: 0, - dataCost: 0, - gasCost: 0 - }); - } - uint256 blockOfInterest = STFLib.getEffectivePendingBlockNumber(_timestamp); - return FeeLib.getManaBaseFeeComponentsAt(blockOfInterest, _timestamp, _inFeeAsset); } diff --git a/l1-contracts/src/core/messagebridge/Inbox.sol b/l1-contracts/src/core/messagebridge/Inbox.sol index 4ad20884cef0..8998d1656785 100644 --- a/l1-contracts/src/core/messagebridge/Inbox.sol +++ b/l1-contracts/src/core/messagebridge/Inbox.sol @@ -20,6 +20,7 @@ contract Inbox is IInbox { using FrontierLib for FrontierLib.Tree; address public immutable ROLLUP; + uint256 public immutable VERSION; uint256 internal immutable HEIGHT; uint256 internal immutable SIZE; @@ -37,8 +38,9 @@ contract Inbox is IInbox { // as it can more easily figure out if it can just skip looking for events for a time period. uint256 public totalMessagesInserted = 0; - constructor(address _rollup, uint256 _height) { + constructor(address _rollup, uint256 _version, uint256 _height) { ROLLUP = _rollup; + VERSION = _version; HEIGHT = _height; SIZE = 2 ** _height; @@ -67,6 +69,9 @@ contract Inbox is IInbox { uint256(_recipient.actor) <= Constants.MAX_FIELD_VALUE, Errors.Inbox__ActorTooLarge(_recipient.actor) ); + require( + _recipient.version == VERSION, Errors.Inbox__VersionMismatch(_recipient.version, VERSION) + ); require(uint256(_content) <= Constants.MAX_FIELD_VALUE, Errors.Inbox__ContentTooLarge(_content)); require( uint256(_secretHash) <= Constants.MAX_FIELD_VALUE, diff --git a/l1-contracts/src/core/messagebridge/Outbox.sol b/l1-contracts/src/core/messagebridge/Outbox.sol index 858cd3cc3100..6ae513b67bc1 100644 --- a/l1-contracts/src/core/messagebridge/Outbox.sol +++ b/l1-contracts/src/core/messagebridge/Outbox.sol @@ -2,12 +2,12 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.27; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol"; import {Hash} from "@aztec/core/libraries/crypto/Hash.sol"; import {MerkleLib} from "@aztec/core/libraries/crypto/MerkleLib.sol"; import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; -import {Rollup} from "@aztec/core/Rollup.sol"; /** * @title Outbox @@ -25,11 +25,13 @@ contract Outbox is IOutbox { mapping(uint256 => bool) nullified; } - Rollup public immutable ROLLUP; + IRollup public immutable ROLLUP; + uint256 public immutable VERSION; mapping(uint256 l2BlockNumber => RootData) internal roots; - constructor(address _rollup) { - ROLLUP = Rollup(_rollup); + constructor(address _rollup, uint256 _version) { + ROLLUP = IRollup(_rollup); + VERSION = _version; } /** @@ -76,6 +78,10 @@ contract Outbox is IOutbox { require( _l2BlockNumber <= ROLLUP.getProvenBlockNumber(), Errors.Outbox__BlockNotProven(_l2BlockNumber) ); + require( + _message.sender.version == VERSION, + Errors.Outbox__VersionMismatch(_message.sender.version, VERSION) + ); require( msg.sender == _message.recipient.actor, diff --git a/l1-contracts/src/governance/Registry.sol b/l1-contracts/src/governance/Registry.sol index f18989d73aec..6caf59fbfaaf 100644 --- a/l1-contracts/src/governance/Registry.sol +++ b/l1-contracts/src/governance/Registry.sol @@ -2,12 +2,18 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.27; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; - -import {DataStructures} from "@aztec/governance/libraries/DataStructures.sol"; import {Errors} from "@aztec/governance/libraries/Errors.sol"; - import {Ownable} from "@oz/access/Ownable.sol"; +import {IERC20} from "@oz/token/ERC20/IERC20.sol"; +import {RewardDistributor, IRewardDistributor} from "./RewardDistributor.sol"; + +struct RegistryStorage { + mapping(uint256 version => IRollup rollup) versionToRollup; + uint256[] versions; + address governance; +} /** * @title Registry @@ -15,73 +21,54 @@ import {Ownable} from "@oz/access/Ownable.sol"; * @notice Keeps track of addresses of current rollup and historical addresses. */ contract Registry is IRegistry, Ownable { - uint256 public override(IRegistry) numberOfVersions; + IRewardDistributor internal immutable REWARD_DISTRIBUTOR; - DataStructures.RegistrySnapshot internal currentSnapshot; - mapping(uint256 version => DataStructures.RegistrySnapshot snapshot) internal snapshots; - mapping(address rollup => uint256 version) internal rollupToVersion; + RegistryStorage internal $; - constructor(address _owner) Ownable(_owner) { - // Inserts a "dead" rollup at version 0 - // This is simply done to make first version 1, which fits better with the rest of the system - _upgrade(address(0xdead)); + constructor(address _owner, IERC20 _rewardAsset) Ownable(_owner) { + REWARD_DISTRIBUTOR = IRewardDistributor( + address(new RewardDistributor(_rewardAsset, IRegistry(address(this)), _owner)) + ); } - /** - * @notice Returns the address of the rollup contract - * @return The rollup address - */ - function getRollup() external view override(IRegistry) returns (address) { - return currentSnapshot.rollup; + function addRollup(IRollup _rollup) external override(IRegistry) onlyOwner { + uint256 version = _rollup.getVersion(); + require( + address($.versionToRollup[version]) == address(0), + Errors.Registry__RollupAlreadyRegistered(address(_rollup)) + ); + $.versionToRollup[version] = _rollup; + $.versions.push(version); + + emit InstanceAdded(address(_rollup), version); } - /** - * @notice Returns the version for a specific rollup contract or reverts if not listed - * @param _rollup - The address of the rollup contract - * @return The version of the rollup contract - */ - function getVersionFor(address _rollup) external view override(IRegistry) returns (uint256) { - (uint256 version, bool exists) = _getVersionFor(_rollup); - require(exists, Errors.Registry__RollupNotRegistered(_rollup)); - return version; + function updateGovernance(address _governance) external override(IRegistry) onlyOwner { + $.governance = _governance; + emit GovernanceUpdated(_governance); } /** - * @notice Returns whther the rollup is registered - * @param _rollup - The address of the rollup contract - * @return Whether the rollup is registered + * @notice Returns the address of the rollup contract + * @return The rollup address */ - function isRollupRegistered(address _rollup) external view override(IRegistry) returns (bool) { - (, bool exists) = _getVersionFor(_rollup); - return exists; + function getCanonicalRollup() external view override(IRegistry) returns (IRollup) { + require($.versions.length > 0, Errors.Registry__NoRollupsRegistered()); + return $.versionToRollup[$.versions[$.versions.length - 1]]; } - /** - * @notice Fetches a snapshot of the registry indicated by `version` - * @dev the version is 0 indexed, so the first snapshot is version 0. - * @param _version - The version of the rollup to return (i.e. which snapshot) - * @return the snapshot - */ - function getSnapshot(uint256 _version) - external - view - override(IRegistry) - returns (DataStructures.RegistrySnapshot memory) - { - return snapshots[_version]; + function getRollup(uint256 _version) external view override(IRegistry) returns (IRollup) { + IRollup rollup = $.versionToRollup[_version]; + require(address(rollup) != address(0), Errors.Registry__RollupNotRegistered(_version)); + return rollup; } - /** - * @notice Returns the current snapshot of the registry - * @return The current snapshot - */ - function getCurrentSnapshot() - external - view - override(IRegistry) - returns (DataStructures.RegistrySnapshot memory) - { - return currentSnapshot; + function numberOfVersions() external view override(IRegistry) returns (uint256) { + return $.versions.length; + } + + function getVersion(uint256 _index) external view override(IRegistry) returns (uint256) { + return $.versions[_index]; } /** @@ -89,40 +76,10 @@ contract Registry is IRegistry, Ownable { * @return The governance address */ function getGovernance() external view override(IRegistry) returns (address) { - return owner(); - } - - /** - * @notice Creates a new snapshot of the registry - * - * @dev Only callable by the owner - * @dev Reverts if the rollup is already registered - * - * @param _rollup - The address of the rollup contract - * @return The version of the new snapshot - */ - function upgrade(address _rollup) public override(IRegistry) onlyOwner returns (uint256) { - return _upgrade(_rollup); - } - - function _upgrade(address _rollup) internal returns (uint256) { - (, bool exists) = _getVersionFor(_rollup); - require(!exists, Errors.Registry__RollupAlreadyRegistered(_rollup)); - - DataStructures.RegistrySnapshot memory newSnapshot = - DataStructures.RegistrySnapshot(_rollup, block.number); - currentSnapshot = newSnapshot; - uint256 version = numberOfVersions++; - snapshots[version] = newSnapshot; - rollupToVersion[_rollup] = version; - - emit InstanceAdded(_rollup, version); - - return version; + return $.governance; } - function _getVersionFor(address _rollup) internal view returns (uint256 version, bool exists) { - version = rollupToVersion[_rollup]; - return (version, version > 0 || snapshots[0].rollup == _rollup); + function getRewardDistributor() external view override(IRegistry) returns (IRewardDistributor) { + return REWARD_DISTRIBUTOR; } } diff --git a/l1-contracts/src/governance/RewardDistributor.sol b/l1-contracts/src/governance/RewardDistributor.sol index 1f746fa7b13b..ee0d29767930 100644 --- a/l1-contracts/src/governance/RewardDistributor.sol +++ b/l1-contracts/src/governance/RewardDistributor.sol @@ -20,16 +20,11 @@ contract RewardDistributor is IRewardDistributor, Ownable { uint256 public constant BLOCK_REWARD = 50e18; IERC20 public immutable ASSET; - IRegistry public registry; + IRegistry public immutable REGISTRY; constructor(IERC20 _asset, IRegistry _registry, address _owner) Ownable(_owner) { ASSET = _asset; - registry = _registry; - } - - function updateRegistry(IRegistry _registry) external override(IRewardDistributor) onlyOwner { - registry = _registry; - emit RegistryUpdated(_registry); + REGISTRY = _registry; } /** @@ -77,6 +72,6 @@ contract RewardDistributor is IRewardDistributor, Ownable { } function canonicalRollup() public view override(IRewardDistributor) returns (address) { - return registry.getRollup(); + return address(REGISTRY.getCanonicalRollup()); } } diff --git a/l1-contracts/src/governance/interfaces/IRegistry.sol b/l1-contracts/src/governance/interfaces/IRegistry.sol index 5b300d3fab17..e5fb116086b4 100644 --- a/l1-contracts/src/governance/interfaces/IRegistry.sol +++ b/l1-contracts/src/governance/interfaces/IRegistry.sol @@ -1,39 +1,31 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.27; -import {DataStructures} from "@aztec/governance/libraries/DataStructures.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; +import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol"; interface IRegistry { event InstanceAdded(address indexed instance, uint256 indexed version); + event GovernanceUpdated(address indexed governance); - // docs:start:registry_upgrade - function upgrade(address _rollup) external returns (uint256); - // docs:end:registry_upgrade + function addRollup(IRollup _rollup) external; + function updateGovernance(address _governance) external; + + // docs:start:registry_get_canonical_rollup + function getCanonicalRollup() external view returns (IRollup); + // docs:end:registry_get_canonical_rollup // docs:start:registry_get_rollup - function getRollup() external view returns (address); + function getRollup(uint256 _chainId) external view returns (IRollup); // docs:end:registry_get_rollup - // docs:start:registry_get_version_for - function getVersionFor(address _rollup) external view returns (uint256); - // docs:end:registry_get_version_for - - // docs:start:registry_get_snapshot - function getSnapshot(uint256 _version) - external - view - returns (DataStructures.RegistrySnapshot memory); - // docs:end:registry_get_snapshot - - // docs:start:registry_get_current_snapshot - function getCurrentSnapshot() external view returns (DataStructures.RegistrySnapshot memory); - // docs:end:registry_get_current_snapshot - // docs:start:registry_number_of_versions function numberOfVersions() external view returns (uint256); // docs:end:registry_number_of_versions - function isRollupRegistered(address _rollup) external view returns (bool); - function getGovernance() external view returns (address); + + function getRewardDistributor() external view returns (IRewardDistributor); + + function getVersion(uint256 _index) external view returns (uint256); } diff --git a/l1-contracts/src/governance/interfaces/IRewardDistributor.sol b/l1-contracts/src/governance/interfaces/IRewardDistributor.sol index 06a8bb766871..7eb18874f2e8 100644 --- a/l1-contracts/src/governance/interfaces/IRewardDistributor.sol +++ b/l1-contracts/src/governance/interfaces/IRewardDistributor.sol @@ -1,12 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.27; -import {IRegistry} from "./IRegistry.sol"; - interface IRewardDistributor { - event RegistryUpdated(IRegistry indexed registry); - - function updateRegistry(IRegistry _registry) external; function claim(address _to) external returns (uint256); function claimBlockRewards(address _to, uint256 _amount) external returns (uint256); function canonicalRollup() external view returns (address); diff --git a/l1-contracts/src/governance/libraries/DataStructures.sol b/l1-contracts/src/governance/libraries/DataStructures.sol index 9c8062d27539..1e567806694c 100644 --- a/l1-contracts/src/governance/libraries/DataStructures.sol +++ b/l1-contracts/src/governance/libraries/DataStructures.sol @@ -11,18 +11,6 @@ import {IPayload} from "@aztec/governance/interfaces/IPayload.sol"; * @notice Library that contains data structures used throughout Aztec governance */ library DataStructures { - // docs:start:registry_snapshot - /** - * @notice Struct for storing address of cross communication components and the block number when it was updated - * @param rollup - The address of the rollup contract - * @param blockNumber - The block number of the snapshot - */ - struct RegistrySnapshot { - address rollup; - uint256 blockNumber; - } - // docs:end:registry_snapshot - struct ProposeConfiguration { Timestamp lockDelay; uint256 lockAmount; diff --git a/l1-contracts/src/governance/libraries/Errors.sol b/l1-contracts/src/governance/libraries/Errors.sol index 66e74e62d9c0..b37b4b6cd196 100644 --- a/l1-contracts/src/governance/libraries/Errors.sol +++ b/l1-contracts/src/governance/libraries/Errors.sol @@ -61,7 +61,8 @@ library Errors { error CoinIssuer__InsufficientMintAvailable(uint256 available, uint256 needed); // 0xa1cc8799 error Registry__RollupAlreadyRegistered(address rollup); // 0x3c34eabf - error Registry__RollupNotRegistered(address rollup); // 0xa1fee4cf + error Registry__RollupNotRegistered(uint256 version); + error Registry__NoRollupsRegistered(); error RewardDistributor__InvalidCaller(address caller, address canonical); // 0xb95e39f6 } diff --git a/l1-contracts/src/governance/proposer/GovernanceProposer.sol b/l1-contracts/src/governance/proposer/GovernanceProposer.sol index 734a42172e53..412ff13da868 100644 --- a/l1-contracts/src/governance/proposer/GovernanceProposer.sol +++ b/l1-contracts/src/governance/proposer/GovernanceProposer.sol @@ -27,7 +27,7 @@ contract GovernanceProposer is IGovernanceProposer, EmpireBase { } function getInstance() public view override(EmpireBase, IGovernanceProposer) returns (address) { - return REGISTRY.getRollup(); + return address(REGISTRY.getCanonicalRollup()); } function _execute(IPayload _proposal) internal override(EmpireBase) returns (bool) { diff --git a/l1-contracts/src/mock/FeeAssetHandler.sol b/l1-contracts/src/mock/FeeAssetHandler.sol index 2b62ce552ba2..0e536fb24d1d 100644 --- a/l1-contracts/src/mock/FeeAssetHandler.sol +++ b/l1-contracts/src/mock/FeeAssetHandler.sol @@ -20,11 +20,11 @@ contract FeeAssetHandler is IFeeAssetHandler, Ownable { mintAmount = _mintAmount; } - function mint(address _recipient) external override { + function mint(address _recipient) external override(IFeeAssetHandler) { FEE_ASSET.mint(_recipient, mintAmount); } - function setMintAmount(uint256 _amount) external override onlyOwner { + function setMintAmount(uint256 _amount) external override(IFeeAssetHandler) onlyOwner { mintAmount = _amount; emit MintAmountSet(_amount); } diff --git a/l1-contracts/src/mock/MockFeeJuicePortal.sol b/l1-contracts/src/mock/MockFeeJuicePortal.sol index 0d180556754a..2a9021ba255a 100644 --- a/l1-contracts/src/mock/MockFeeJuicePortal.sol +++ b/l1-contracts/src/mock/MockFeeJuicePortal.sol @@ -3,14 +3,17 @@ pragma solidity >=0.8.27; import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol"; -import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; +import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol"; import {TestERC20} from "@aztec/mock/TestERC20.sol"; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; contract MockFeeJuicePortal is IFeeJuicePortal { IERC20 public immutable UNDERLYING; bytes32 public constant L2_TOKEN_ADDRESS = bytes32(0); - IRegistry public constant REGISTRY = IRegistry(address(0)); + IRollup public constant ROLLUP = IRollup(address(0)); + uint256 public constant VERSION = 0; + IInbox public constant INBOX = IInbox(address(0)); constructor() { UNDERLYING = new TestERC20("test", "TEST", msg.sender); @@ -28,8 +31,4 @@ contract MockFeeJuicePortal is IFeeJuicePortal { { return (bytes32(0), 0); } - - function canonicalRollup() external pure override(IFeeJuicePortal) returns (address) { - return address(0); - } } diff --git a/l1-contracts/src/mock/StakingAssetHandler.sol b/l1-contracts/src/mock/StakingAssetHandler.sol index 70b1919882d4..764c24465fab 100644 --- a/l1-contracts/src/mock/StakingAssetHandler.sol +++ b/l1-contracts/src/mock/StakingAssetHandler.sol @@ -108,7 +108,11 @@ contract StakingAssetHandler is IStakingAssetHandler, Ownable { emit AddValidatorPermissionGranted(_owner); } - function addValidator(address _attester, address _proposer) external override onlyCanAddValidator { + function addValidator(address _attester, address _proposer) + external + override(IStakingAssetHandler) + onlyCanAddValidator + { bool needsToMint = STAKING_ASSET.balanceOf(address(this)) < depositAmount; bool canMint = block.timestamp - lastMintTimestamp >= mintInterval; @@ -124,38 +128,50 @@ contract StakingAssetHandler is IStakingAssetHandler, Ownable { emit ValidatorAdded(_attester, _proposer, withdrawer); } - function setRollup(address _rollup) external override onlyOwner { + function setRollup(address _rollup) external override(IStakingAssetHandler) onlyOwner { rollup = IStaking(_rollup); emit RollupUpdated(_rollup); } - function setDepositAmount(uint256 _amount) external override onlyOwner { + function setDepositAmount(uint256 _amount) external override(IStakingAssetHandler) onlyOwner { depositAmount = _amount; emit DepositAmountUpdated(_amount); } - function setMintInterval(uint256 _interval) external override onlyOwner { + function setMintInterval(uint256 _interval) external override(IStakingAssetHandler) onlyOwner { mintInterval = _interval; emit IntervalUpdated(_interval); } - function setDepositsPerMint(uint256 _depositsPerMint) external override onlyOwner { + function setDepositsPerMint(uint256 _depositsPerMint) + external + override(IStakingAssetHandler) + onlyOwner + { require(_depositsPerMint > 0, CannotMintZeroAmount()); depositsPerMint = _depositsPerMint; emit DepositsPerMintUpdated(_depositsPerMint); } - function setWithdrawer(address _withdrawer) external override onlyOwner { + function setWithdrawer(address _withdrawer) external override(IStakingAssetHandler) onlyOwner { withdrawer = _withdrawer; emit WithdrawerUpdated(_withdrawer); } - function grantAddValidatorPermission(address _address) external override onlyOwner { + function grantAddValidatorPermission(address _address) + external + override(IStakingAssetHandler) + onlyOwner + { canAddValidator[_address] = true; emit AddValidatorPermissionGranted(_address); } - function revokeAddValidatorPermission(address _address) external override onlyOwner { + function revokeAddValidatorPermission(address _address) + external + override(IStakingAssetHandler) + onlyOwner + { canAddValidator[_address] = false; emit AddValidatorPermissionRevoked(_address); } diff --git a/l1-contracts/test/Inbox.t.sol b/l1-contracts/test/Inbox.t.sol index 96375d4c205a..5d0cec26cf3e 100644 --- a/l1-contracts/test/Inbox.t.sol +++ b/l1-contracts/test/Inbox.t.sol @@ -26,7 +26,7 @@ contract InboxTest is Test { function setUp() public { address rollup = address(this); - inbox = new InboxHarness(rollup, HEIGHT); + inbox = new InboxHarness(rollup, version, HEIGHT); emptyTreeRoot = inbox.getEmptyRoot(); } @@ -132,6 +132,17 @@ contract InboxTest is Test { inbox.sendL2Message(message.recipient, message.content, message.secretHash); } + function testRevertIfVersionMismatch() public { + DataStructures.L1ToL2Msg memory message = _fakeMessage(); + message.recipient.version = version + 1; + vm.expectRevert( + abi.encodeWithSelector( + Errors.Inbox__VersionMismatch.selector, message.recipient.version, version + ) + ); + inbox.sendL2Message(message.recipient, message.content, message.secretHash); + } + function testRevertIfContentTooLarge() public { DataStructures.L1ToL2Msg memory message = _fakeMessage(); message.content = bytes32(Constants.P); diff --git a/l1-contracts/test/MultiProof.t.sol b/l1-contracts/test/MultiProof.t.sol index 09552d42fc1c..986c9cbbc129 100644 --- a/l1-contracts/test/MultiProof.t.sol +++ b/l1-contracts/test/MultiProof.t.sol @@ -20,8 +20,9 @@ import { import {Rollup} from "@aztec/core/Rollup.sol"; import {Strings} from "@oz/utils/Strings.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; +import {IERC20} from "@oz/token/ERC20/IERC20.sol"; -import {RollupBase, IInstance} from "./base/RollupBase.sol"; +import {RollupBase, IInstance, IRollup} from "./base/RollupBase.sol"; // solhint-disable comprehensive-interface @@ -69,19 +70,15 @@ contract MultiProofTest is RollupBase { vm.warp(initialTime); } - registry = new Registry(address(this)); - feeJuicePortal = new FeeJuicePortal( - address(registry), address(testERC20), bytes32(Constants.FEE_JUICE_ADDRESS) - ); - testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); - feeJuicePortal.initialize(); - rewardDistributor = new RewardDistributor(testERC20, registry, address(this)); + registry = new Registry(address(this), IERC20(address(testERC20))); + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); + testERC20.mint(address(rewardDistributor), 1e6 ether); rollup = IInstance( address( new Rollup( - feeJuicePortal, + testERC20, rewardDistributor, testERC20, address(this), @@ -91,7 +88,12 @@ contract MultiProofTest is RollupBase { ) ); - registry.upgrade(address(rollup)); + feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal())); + + testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); + feeJuicePortal.initialize(); + + registry.addRollup(IRollup(address(rollup))); _; } diff --git a/l1-contracts/test/Outbox.t.sol b/l1-contracts/test/Outbox.t.sol index 806ef8c66c00..2bb44c8d106b 100644 --- a/l1-contracts/test/Outbox.t.sol +++ b/l1-contracts/test/Outbox.t.sol @@ -35,7 +35,7 @@ contract OutboxTest is Test { ROLLUP_CONTRACT = address(new FakeRollup()); FakeRollup(ROLLUP_CONTRACT).setProvenBlockNum(1); - outbox = new Outbox(ROLLUP_CONTRACT); + outbox = new Outbox(ROLLUP_CONTRACT, AZTEC_VERSION); zeroedTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); merkleTestUtil = new MerkleTestUtil(); } @@ -115,6 +115,19 @@ contract OutboxTest is Test { outbox.consume(fakeMessage, 1, 1, path); } + function testRevertIfVersionMismatch() public { + DataStructures.L2ToL1Msg memory message = _fakeMessage(address(this)); + (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); + + message.sender.version = AZTEC_VERSION + 1; + vm.expectRevert( + abi.encodeWithSelector( + Errors.Outbox__VersionMismatch.selector, message.sender.version, AZTEC_VERSION + ) + ); + outbox.consume(message, 1, 1, path); + } + function testRevertIfNothingInsertedAtBlockNumber() public { uint256 blockNumber = 1; DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index b9f240b4a6d0..09c5798ef115 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -17,6 +17,7 @@ import {Rollup} from "@aztec/core/Rollup.sol"; import {TestConstants} from "./harnesses/TestConstants.sol"; import { + IRollup, IRollupCore, BlockLog, SubmitEpochRootProofArgs, @@ -33,7 +34,7 @@ import {TestConstants} from "./harnesses/TestConstants.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol"; import {ProposeArgs, OracleInput, ProposeLib} from "@aztec/core/libraries/rollup/ProposeLib.sol"; - +import {IERC20} from "@oz/token/ERC20/IERC20.sol"; import { Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeLib } from "@aztec/core/libraries/TimeLib.sol"; @@ -85,19 +86,14 @@ contract RollupTest is RollupBase { vm.warp(initialTime); } - registry = new Registry(address(this)); - feeJuicePortal = new FeeJuicePortal( - address(registry), address(testERC20), bytes32(Constants.FEE_JUICE_ADDRESS) - ); - testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); - feeJuicePortal.initialize(); - rewardDistributor = new RewardDistributor(testERC20, registry, address(this)); + registry = new Registry(address(this), IERC20(address(testERC20))); + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); testERC20.mint(address(rewardDistributor), 1e6 ether); rollup = IInstance( address( new Rollup( - feeJuicePortal, + testERC20, rewardDistributor, testERC20, address(this), @@ -108,7 +104,12 @@ contract RollupTest is RollupBase { ); inbox = Inbox(address(rollup.getInbox())); outbox = Outbox(address(rollup.getOutbox())); - registry.upgrade(address(rollup)); + registry.addRollup(IRollup(address(rollup))); + + feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal())); + + testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); + feeJuicePortal.initialize(); merkleTestUtil = new MerkleTestUtil(); _; @@ -291,14 +292,13 @@ contract RollupTest is RollupBase { } function testNonZeroDaFee() public setUpFor("mixed_block_1") { - registry.upgrade(address(0xbeef)); - DecoderBase.Full memory full = load("mixed_block_1"); DecoderBase.Data memory data = full.block; bytes memory header = data.header; assembly { mstore(add(header, add(0x20, 0x0208)), 1) } + header = _updateHeaderVersion(header, rollup.getVersion()); bytes32[] memory txHashes = new bytes32[](0); // We jump to the time of the block. (unless it is in the past) @@ -317,15 +317,14 @@ contract RollupTest is RollupBase { rollup.propose(args, signatures, data.blobInputs); } - function testNonZeroL2Fee() public setUpFor("mixed_block_1") { - registry.upgrade(address(0xbeef)); - + function testInvalidL2Fee() public setUpFor("mixed_block_1") { DecoderBase.Full memory full = load("mixed_block_1"); DecoderBase.Data memory data = full.block; bytes memory header = data.header; assembly { mstore(add(header, add(0x20, 0x0228)), 1) } + header = _updateHeaderVersion(header, rollup.getVersion()); bytes32[] memory txHashes = new bytes32[](0); // We jump to the time of the block. (unless it is in the past) @@ -333,8 +332,12 @@ contract RollupTest is RollupBase { skipBlobCheck(address(rollup)); + uint256 expectedFee = rollup.getManaBaseFeeAt(Timestamp.wrap(block.timestamp), true); + // When not canonical, we expect the fee to be 0 - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidManaBaseFee.selector, 0, 1)); + vm.expectRevert( + abi.encodeWithSelector(Errors.Rollup__InvalidManaBaseFee.selector, expectedFee, 1) + ); ProposeArgs memory args = ProposeArgs({ header: header, archive: data.archive, @@ -403,6 +406,7 @@ contract RollupTest is RollupBase { skipBlobCheck(address(rollup)); interim.baseFee = rollup.getManaBaseFeeAt(Timestamp.wrap(block.timestamp), true); + header = _updateHeaderVersion(header, rollup.getVersion()); header = _updateHeaderBaseFee(header, interim.baseFee); header = _updateHeaderManaUsed(header, interim.manaUsed); // We mess up the fees and say that someone is paying a massive priority which surpass the amount available. @@ -699,6 +703,7 @@ contract RollupTest is RollupBase { // TODO: Hardcoding offsets in the middle of tests is annoying to say the least. mstore(add(header, add(0x20, 0x0174)), 0x420) } + header = _updateHeaderVersion(header, rollup.getVersion()); skipBlobCheck(address(rollup)); vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidBlockNumber.selector, 1, 0x420)); ProposeArgs memory args = ProposeArgs({ @@ -714,6 +719,7 @@ contract RollupTest is RollupBase { function testRevertInvalidChainId() public setUpFor("empty_block_1") { DecoderBase.Data memory data = load("empty_block_1").block; bytes memory header = data.header; + header = _updateHeaderVersion(header, rollup.getVersion()); bytes32 archive = data.archive; bytes32[] memory txHashes = new bytes32[](0); @@ -742,7 +748,9 @@ contract RollupTest is RollupBase { mstore(add(header, add(0x20, 0x0154)), 0x420) } skipBlobCheck(address(rollup)); - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 1, 0x420)); + vm.expectRevert( + abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, rollup.getVersion(), 0x420) + ); ProposeArgs memory args = ProposeArgs({ header: header, archive: archive, @@ -756,6 +764,7 @@ contract RollupTest is RollupBase { function testRevertInvalidTimestamp() public setUpFor("empty_block_1") { DecoderBase.Data memory data = load("empty_block_1").block; bytes memory header = data.header; + header = _updateHeaderVersion(header, rollup.getVersion()); bytes32 archive = data.archive; bytes32[] memory txHashes = new bytes32[](0); diff --git a/l1-contracts/test/base/RollupBase.sol b/l1-contracts/test/base/RollupBase.sol index d5186f09c496..e25bd47fb036 100644 --- a/l1-contracts/test/base/RollupBase.sol +++ b/l1-contracts/test/base/RollupBase.sol @@ -5,7 +5,10 @@ import {DecoderBase} from "./DecoderBase.sol"; import {IInstance} from "@aztec/core/interfaces/IInstance.sol"; import { - BlockLog, SubmitEpochRootProofArgs, PublicInputArgs + IRollup, + BlockLog, + SubmitEpochRootProofArgs, + PublicInputArgs } from "@aztec/core/interfaces/IRollup.sol"; import {Constants} from "@aztec/core/libraries/ConstantsGen.sol"; import {Strings} from "@oz/utils/Strings.sol"; @@ -108,6 +111,17 @@ contract RollupBase is DecoderBase { ); } + function _updateHeaderVersion(bytes memory _header, uint256 _version) + internal + pure + returns (bytes memory) + { + assembly { + mstore(add(_header, add(0x20, 0x0154)), _version) + } + return _header; + } + function _updateHeaderBaseFee(bytes memory _header, uint256 _baseFee) internal pure @@ -130,6 +144,17 @@ contract RollupBase is DecoderBase { return _header; } + function _updateHeaderInboxRoot(bytes memory _header, bytes32 _inboxRoot) + internal + pure + returns (bytes memory) + { + assembly { + mstore(add(_header, add(0x20, 0x0064)), _inboxRoot) + } + return _header; + } + function _updateHeaderTotalFees(bytes memory _header, uint256 _totalFees) internal pure @@ -185,6 +210,7 @@ contract RollupBase is DecoderBase { uint256 baseFee = rollup.getManaBaseFeeAt( Timestamp.wrap(full.block.decodedHeader.globalVariables.timestamp), true ); + header = _updateHeaderVersion(header, rollup.getVersion()); header = _updateHeaderBaseFee(header, baseFee); header = _updateHeaderManaUsed(header, _manaUsed); header = _updateHeaderTotalFees(header, _manaUsed * baseFee); @@ -195,6 +221,9 @@ contract RollupBase is DecoderBase { vm.warp(max(block.timestamp, full.block.decodedHeader.globalVariables.timestamp)); _populateInbox(full.populate.sender, full.populate.recipient, full.populate.l1ToL2Content); + header = _updateHeaderInboxRoot( + header, rollup.getInbox().getRoot(full.block.decodedHeader.globalVariables.blockNumber) + ); { bytes32[] memory blobHashes = new bytes32[](1); @@ -276,11 +305,12 @@ contract RollupBase is DecoderBase { function _populateInbox(address _sender, bytes32 _recipient, bytes32[] memory _contents) internal { inbox = Inbox(address(rollup.getInbox())); + uint256 version = rollup.getVersion(); for (uint256 i = 0; i < _contents.length; i++) { vm.prank(_sender); inbox.sendL2Message( - DataStructures.L2Actor({actor: _recipient, version: 1}), _contents[i], bytes32(0) + DataStructures.L2Actor({actor: _recipient, version: version}), _contents[i], bytes32(0) ); } } diff --git a/l1-contracts/test/benchmark/happy.t.sol b/l1-contracts/test/benchmark/happy.t.sol index 0e532234faf7..d4a5e2ba8d07 100644 --- a/l1-contracts/test/benchmark/happy.t.sol +++ b/l1-contracts/test/benchmark/happy.t.sol @@ -31,7 +31,8 @@ import {TestConstants} from "../harnesses/TestConstants.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol"; import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol"; -import {IRewardDistributor, IRegistry} from "@aztec/governance/interfaces/IRewardDistributor.sol"; +import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol"; +import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; import {ProposeArgs, OracleInput, ProposeLib} from "@aztec/core/libraries/rollup/ProposeLib.sol"; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; import { @@ -137,7 +138,7 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase { fakeCanonical = new FakeCanonical(IERC20(address(asset))); rollup = new Rollup( - IFeeJuicePortal(address(fakeCanonical)), + asset, IRewardDistributor(address(fakeCanonical)), asset, address(this), @@ -185,6 +186,7 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase { asset.mint(address(this), TestConstants.AZTEC_MINIMUM_STAKE * VALIDATOR_COUNT); asset.approve(address(rollup), TestConstants.AZTEC_MINIMUM_STAKE * VALIDATOR_COUNT); rollup.cheat__InitialiseValidatorSet(initialValidators); + asset.mint(address(rollup.getFeeAssetPortal()), 1e30); asset.transferOwnership(address(fakeCanonical)); } @@ -217,6 +219,8 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase { address proposer = rollup.getCurrentProposer(); + uint256 version = rollup.getVersion(); + // Updating the header with important information! assembly { let headerRef := add(header, 0x20) @@ -231,6 +235,7 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase { // Store the modified word back mstore(add(headerRef, 0x20), word) + mstore(add(headerRef, 0x0154), version) mstore(add(headerRef, 0x0174), bn) mstore(add(headerRef, 0x0194), slotNumber) mstore(add(headerRef, 0x01b4), ts) diff --git a/l1-contracts/test/fee_portal/depositToAztecPublic.t.sol b/l1-contracts/test/fee_portal/depositToAztecPublic.t.sol index 0f24592dfce5..ce81143a547d 100644 --- a/l1-contracts/test/fee_portal/depositToAztecPublic.t.sol +++ b/l1-contracts/test/fee_portal/depositToAztecPublic.t.sol @@ -9,6 +9,7 @@ import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol"; import {Constants} from "@aztec/core/libraries/ConstantsGen.sol"; import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol"; import {Rollup} from "@aztec/core/Rollup.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; import {TestConstants} from "../harnesses/TestConstants.sol"; import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; import {Hash} from "@aztec/core/libraries/crypto/Hash.sol"; @@ -27,16 +28,12 @@ contract DepositToAztecPublic is Test { RewardDistributor internal rewardDistributor; function setUp() public { - registry = new Registry(OWNER); token = new TestERC20("test", "TEST", address(this)); - feeJuicePortal = - new FeeJuicePortal(address(registry), address(token), bytes32(Constants.FEE_JUICE_ADDRESS)); + registry = new Registry(OWNER, token); - token.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); - feeJuicePortal.initialize(); rewardDistributor = new RewardDistributor(token, registry, address(this)); rollup = new Rollup( - feeJuicePortal, + token, rewardDistributor, token, address(this), @@ -44,8 +41,12 @@ contract DepositToAztecPublic is Test { TestConstants.getRollupConfigInput() ); + feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal())); + token.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); + feeJuicePortal.initialize(); + vm.prank(OWNER); - registry.upgrade(address(rollup)); + registry.addRollup(IRollup(address(rollup))); } function test_RevertGiven_InsufficientBalance() external { @@ -64,29 +65,13 @@ contract DepositToAztecPublic is Test { feeJuicePortal.depositToAztecPublic(bytes32(0x0), 1, bytes32(0x0)); } - function test_GivenSufficientBalance(uint256 _numberOfRollups) external { - // it should create a message for the newest version + function test_GivenSufficientBalance() external { + // it should create a message for the inbox (and its rollup version) // it should transfer the tokens to the portal - // it should insert the message into the newest inbox + // it should insert the message into the inbox // it should emit a {DepositToAztecPublic} event // it should return the key - uint256 numberOfRollups = bound(_numberOfRollups, 1, 5); - for (uint256 i = 0; i < numberOfRollups; i++) { - Rollup freshRollup = new Rollup( - feeJuicePortal, - rewardDistributor, - token, - address(this), - TestConstants.getGenesisState(), - TestConstants.getRollupConfigInput() - ); - vm.prank(OWNER); - registry.upgrade(address(freshRollup)); - } - - assertNotEq(registry.getRollup(), address(rollup)); - bytes32 to = bytes32(0x0); bytes32 secretHash = bytes32(uint256(0x01)); uint256 amount = 100 ether; @@ -96,7 +81,7 @@ contract DepositToAztecPublic is Test { // it has nothing to do with calling the function. DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({ sender: DataStructures.L1Actor(address(feeJuicePortal), block.chainid), - recipient: DataStructures.L2Actor(feeJuicePortal.L2_TOKEN_ADDRESS(), 1 + numberOfRollups), + recipient: DataStructures.L2Actor(feeJuicePortal.L2_TOKEN_ADDRESS(), rollup.getVersion()), content: Hash.sha256ToField(abi.encodeWithSignature("claim(bytes32,uint256)", to, amount)), secretHash: secretHash, index: expectedIndex @@ -107,7 +92,7 @@ contract DepositToAztecPublic is Test { token.mint(address(this), amount); token.approve(address(feeJuicePortal), amount); - Inbox inbox = Inbox(address(Rollup(address(registry.getRollup())).getInbox())); + Inbox inbox = Inbox(address(Rollup(address(registry.getCanonicalRollup())).getInbox())); assertEq(inbox.totalMessagesInserted(), 0); vm.expectEmit(true, true, true, true, address(inbox)); diff --git a/l1-contracts/test/fee_portal/distributeFees.t.sol b/l1-contracts/test/fee_portal/distributeFees.t.sol index 996822de3c96..6a78f4ec5aa7 100644 --- a/l1-contracts/test/fee_portal/distributeFees.t.sol +++ b/l1-contracts/test/fee_portal/distributeFees.t.sol @@ -14,6 +14,7 @@ import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; import {Hash} from "@aztec/core/libraries/crypto/Hash.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; contract DistributeFees is Test { using Hash for DataStructures.L1ToL2Msg; @@ -26,16 +27,12 @@ contract DistributeFees is Test { RewardDistributor internal rewardDistributor; function setUp() public { - registry = new Registry(OWNER); token = new TestERC20("test", "TEST", address(this)); - feeJuicePortal = - new FeeJuicePortal(address(registry), address(token), bytes32(Constants.FEE_JUICE_ADDRESS)); - token.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); - feeJuicePortal.initialize(); + registry = new Registry(OWNER, token); - rewardDistributor = new RewardDistributor(token, registry, address(this)); + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); rollup = new Rollup( - feeJuicePortal, + token, rewardDistributor, token, address(this), @@ -43,8 +40,12 @@ contract DistributeFees is Test { TestConstants.getRollupConfigInput() ); + feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal())); + token.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); + feeJuicePortal.initialize(); + vm.prank(OWNER); - registry.upgrade(address(rollup)); + registry.addRollup(IRollup(address(rollup))); } function test_RevertGiven_TheCallerIsNotTheCanonicalRollup() external { @@ -71,32 +72,13 @@ contract DistributeFees is Test { feeJuicePortal.distributeFees(address(this), Constants.FEE_JUICE_INITIAL_MINT + 1); } - function test_GivenSufficientBalance(uint256 _numberOfRollups) - external - givenTheCallerIsTheCanonicalRollup - { + function test_GivenSufficientBalance() external givenTheCallerIsTheCanonicalRollup { // it should transfer the tokens to the recipient // it should emit a {FeesDistributed} event - uint256 numberOfRollups = bound(_numberOfRollups, 1, 5); - for (uint256 i = 0; i < numberOfRollups; i++) { - Rollup freshRollup = new Rollup( - feeJuicePortal, - rewardDistributor, - token, - address(this), - TestConstants.getGenesisState(), - TestConstants.getRollupConfigInput() - ); - vm.prank(OWNER); - registry.upgrade(address(freshRollup)); - } - assertEq(token.balanceOf(address(this)), 0); - assertNotEq(registry.getRollup(), address(rollup)); - - vm.prank(registry.getRollup()); + vm.prank(address(rollup)); vm.expectEmit(true, true, true, true, address(feeJuicePortal)); emit IFeeJuicePortal.FeesDistributed(address(this), Constants.FEE_JUICE_INITIAL_MINT); feeJuicePortal.distributeFees(address(this), Constants.FEE_JUICE_INITIAL_MINT); diff --git a/l1-contracts/test/fees/FeeRollup.t.sol b/l1-contracts/test/fees/FeeRollup.t.sol index 82ff830f8ed3..8a8bad6e31ea 100644 --- a/l1-contracts/test/fees/FeeRollup.t.sol +++ b/l1-contracts/test/fees/FeeRollup.t.sol @@ -30,7 +30,8 @@ import {TestConstants} from "../harnesses/TestConstants.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol"; import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol"; -import {IRewardDistributor, IRegistry} from "@aztec/governance/interfaces/IRewardDistributor.sol"; +import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol"; +import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; import {ProposeArgs, OracleInput, ProposeLib} from "@aztec/core/libraries/rollup/ProposeLib.sol"; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; import { @@ -56,37 +57,6 @@ import {MinimalFeeModel} from "./MinimalFeeModel.sol"; uint256 constant MANA_TARGET = 100000000; -contract FakeCanonical is IRewardDistributor { - uint256 public constant BLOCK_REWARD = 50e18; - IERC20 public immutable UNDERLYING; - - address public canonicalRollup; - - constructor(IERC20 _asset) { - UNDERLYING = _asset; - } - - function setCanonicalRollup(address _rollup) external { - canonicalRollup = _rollup; - } - - function claim(address _recipient) external returns (uint256) { - TestERC20(address(UNDERLYING)).mint(_recipient, BLOCK_REWARD); - return BLOCK_REWARD; - } - - function claimBlockRewards(address _recipient, uint256 _blocks) external returns (uint256) { - TestERC20(address(UNDERLYING)).mint(_recipient, _blocks * BLOCK_REWARD); - return _blocks * BLOCK_REWARD; - } - - function distributeFees(address _recipient, uint256 _amount) external { - TestERC20(address(UNDERLYING)).mint(_recipient, _amount); - } - - function updateRegistry(IRegistry _registry) external {} -} - contract FeeRollupTest is FeeModelTestPoints, DecoderBase { using stdStorage for StdStorage; @@ -116,7 +86,7 @@ contract FeeRollupTest is FeeModelTestPoints, DecoderBase { address internal coinbase = address(bytes20("MONEY MAKER")); TestERC20 internal asset; - FakeCanonical internal fakeCanonical; + RewardDistributor internal rewardDistributor; constructor() { FeeLib.initialize(MANA_TARGET, EthValue.wrap(100)); @@ -131,12 +101,12 @@ contract FeeRollupTest is FeeModelTestPoints, DecoderBase { asset = new TestERC20("test", "TEST", address(this)); - fakeCanonical = new FakeCanonical(IERC20(address(asset))); - asset.transferOwnership(address(fakeCanonical)); + Registry registry = new Registry(address(this), asset); + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); rollup = new Rollup( - IFeeJuicePortal(address(fakeCanonical)), - IRewardDistributor(address(fakeCanonical)), + asset, + IRewardDistributor(address(rewardDistributor)), asset, address(this), TestConstants.getGenesisState(), @@ -152,11 +122,16 @@ contract FeeRollupTest is FeeModelTestPoints, DecoderBase { provingCostPerMana: TestConstants.AZTEC_PROVING_COST_PER_MANA }) ); - fakeCanonical.setCanonicalRollup(address(rollup)); + + registry.addRollup(IRollup(address(rollup))); + + asset.mint(address(rewardDistributor), 1e6 * rewardDistributor.BLOCK_REWARD()); + asset.mint(address(rollup.getFeeAssetPortal()), 1e30); vm.label(coinbase, "coinbase"); vm.label(address(rollup), "ROLLUP"); - vm.label(address(fakeCanonical), "FAKE CANONICAL"); + vm.label(address(rewardDistributor), "REWARD DISTRIBUTOR"); + vm.label(address(rollup.getFeeAssetPortal()), "FEE ASSET PORTAL"); vm.label(address(asset), "ASSET"); vm.label(rollup.getBurnAddress(), "BURN_ADDRESS"); } @@ -206,6 +181,8 @@ contract FeeRollupTest is FeeModelTestPoints, DecoderBase { // Put coinbase onto the stack address cb = coinbase; + uint256 version = rollup.getVersion(); + // Updating the header with important information! assembly { let headerRef := add(header, 0x20) @@ -220,6 +197,7 @@ contract FeeRollupTest is FeeModelTestPoints, DecoderBase { // Store the modified word back mstore(add(headerRef, 0x20), word) + mstore(add(headerRef, 0x0154), version) mstore(add(headerRef, 0x0174), bn) mstore(add(headerRef, 0x0194), slotNumber) mstore(add(headerRef, 0x01b4), ts) @@ -493,7 +471,7 @@ contract FeeRollupTest is FeeModelTestPoints, DecoderBase { // The reward is not yet distributed, but only accumulated. { - uint256 newFees = fakeCanonical.BLOCK_REWARD() * epochSize / 2 + sequencerFees; + uint256 newFees = rewardDistributor.BLOCK_REWARD() * epochSize / 2 + sequencerFees; assertEq( rollup.getSequencerRewards(coinbase), sequencerRewardsBefore + newFees, @@ -503,7 +481,7 @@ contract FeeRollupTest is FeeModelTestPoints, DecoderBase { { assertEq( rollup.getCollectiveProverRewardsForEpoch(rollup.getEpochForBlock(start)), - fakeCanonical.BLOCK_REWARD() * epochSize / 2 + proverFees, + rewardDistributor.BLOCK_REWARD() * epochSize / 2 + proverFees, "prover rewards" ); } diff --git a/l1-contracts/test/governance/governance-proposer/Base.t.sol b/l1-contracts/test/governance/governance-proposer/Base.t.sol index bbfd7b548287..945a83c13d11 100644 --- a/l1-contracts/test/governance/governance-proposer/Base.t.sol +++ b/l1-contracts/test/governance/governance-proposer/Base.t.sol @@ -7,6 +7,7 @@ import {Registry} from "@aztec/governance/Registry.sol"; import {GovernanceProposer} from "@aztec/governance/proposer/GovernanceProposer.sol"; import {IPayload} from "@aztec/governance/interfaces/IPayload.sol"; +import {TestERC20} from "@aztec/mock/TestERC20.sol"; contract FakeGovernance { address immutable GOVERNANCE_PROPOSER; @@ -29,11 +30,13 @@ contract GovernanceProposerBase is Test { GovernanceProposer internal governanceProposer; function setUp() public virtual { - registry = new Registry(address(this)); + TestERC20 asset = new TestERC20("test", "TEST", address(this)); + registry = new Registry(address(this), asset); governanceProposer = new GovernanceProposer(registry, 667, 1000); governance = new FakeGovernance(address(governanceProposer)); + registry.updateGovernance(address(governance)); registry.transferOwnership(address(governance)); } } diff --git a/l1-contracts/test/governance/governance-proposer/constructor.t.sol b/l1-contracts/test/governance/governance-proposer/constructor.t.sol index 327ef727701d..ce75db3f90bd 100644 --- a/l1-contracts/test/governance/governance-proposer/constructor.t.sol +++ b/l1-contracts/test/governance/governance-proposer/constructor.t.sol @@ -11,7 +11,7 @@ contract FakeRegistry { return address(0x01); } - function getRollup() external pure returns (address) { + function getCanonicalRollup() external pure returns (address) { return address(0x02); } } @@ -53,6 +53,6 @@ contract ConstructorTest is Test { assertEq(g.N(), n); assertEq(g.M(), m); assertEq(g.getExecutor(), address(REGISTRY.getGovernance()), "executor"); - assertEq(g.getInstance(), address(REGISTRY.getRollup()), "instance"); + assertEq(g.getInstance(), address(REGISTRY.getCanonicalRollup()), "instance"); } } diff --git a/l1-contracts/test/governance/governance-proposer/executeProposal.t.sol b/l1-contracts/test/governance/governance-proposer/executeProposal.t.sol index 817269c4c203..20e6fb336512 100644 --- a/l1-contracts/test/governance/governance-proposer/executeProposal.t.sol +++ b/l1-contracts/test/governance/governance-proposer/executeProposal.t.sol @@ -10,6 +10,7 @@ import {Slot, SlotLib, Timestamp} from "@aztec/core/libraries/TimeLib.sol"; import {FaultyGovernance} from "./mocks/FaultyGovernance.sol"; import {FalsyGovernance} from "./mocks/FalsyGovernance.sol"; import {Fakerollup} from "./mocks/Fakerollup.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; contract ExecuteProposalTest is GovernanceProposerBase { using SlotLib for Slot; @@ -21,10 +22,15 @@ contract ExecuteProposalTest is GovernanceProposerBase { function test_GivenCanonicalInstanceHoldNoCode(uint256 _roundNumber) external { // it revert + + // Somehow we added a new rollup, and then its code was deleted. Or the registry implementation differed + address f = address(new Fakerollup()); + vm.prank(registry.getGovernance()); + registry.addRollup(IRollup(f)); + vm.etch(f, ""); + vm.expectRevert( - abi.encodeWithSelector( - Errors.GovernanceProposer__InstanceHaveNoCode.selector, address(0xdead) - ) + abi.encodeWithSelector(Errors.GovernanceProposer__InstanceHaveNoCode.selector, address(f)) ); governanceProposer.executeProposal(_roundNumber); } @@ -32,7 +38,7 @@ contract ExecuteProposalTest is GovernanceProposerBase { modifier givenCanonicalInstanceHoldCode() { validatorSelection = new Fakerollup(); vm.prank(registry.getGovernance()); - registry.upgrade(address(validatorSelection)); + registry.addRollup(IRollup(address(validatorSelection))); // We jump into the future since slot 0, will behave as if already voted in vm.warp(Timestamp.unwrap(validatorSelection.getTimestampForSlot(Slot.wrap(1)))); @@ -223,7 +229,7 @@ contract ExecuteProposalTest is GovernanceProposerBase { // When using a new registry we change the governanceProposer's interpetation of time :O Fakerollup freshInstance = new Fakerollup(); vm.prank(registry.getGovernance()); - registry.upgrade(address(freshInstance)); + registry.addRollup(IRollup(address(freshInstance))); // The old is still there, just not executable. (, IPayload leader, bool executed) = governanceProposer.rounds(address(validatorSelection), 1); diff --git a/l1-contracts/test/governance/governance-proposer/mocks/Fakerollup.sol b/l1-contracts/test/governance/governance-proposer/mocks/Fakerollup.sol index cc4ee196a757..b83d8c625ab6 100644 --- a/l1-contracts/test/governance/governance-proposer/mocks/Fakerollup.sol +++ b/l1-contracts/test/governance/governance-proposer/mocks/Fakerollup.sol @@ -39,4 +39,8 @@ contract Fakerollup { function getCurrentProposer() external pure returns (address) { return address(0); } + + function getVersion() external view returns (uint256) { + return uint256(keccak256(abi.encodePacked(bytes("aztec_rollup"), block.chainid, address(this)))); + } } diff --git a/l1-contracts/test/governance/governance-proposer/vote.t.sol b/l1-contracts/test/governance/governance-proposer/vote.t.sol index 89ba7e4a6ad0..238c274edbfc 100644 --- a/l1-contracts/test/governance/governance-proposer/vote.t.sol +++ b/l1-contracts/test/governance/governance-proposer/vote.t.sol @@ -7,6 +7,7 @@ import {GovernanceProposerBase} from "./Base.t.sol"; import {Errors} from "@aztec/governance/libraries/Errors.sol"; import {Slot, SlotLib, Timestamp} from "@aztec/core/libraries/TimeLib.sol"; import {Fakerollup} from "./mocks/Fakerollup.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; contract VoteTest is GovernanceProposerBase { using SlotLib for Slot; @@ -31,10 +32,15 @@ contract VoteTest is GovernanceProposerBase { function test_GivenCanonicalRollupHoldNoCode() external whenProposalHoldCode { // it revert + + // Somehow we added a new rollup, and then its code was deleted. Or the registry implementation differed + address f = address(new Fakerollup()); + vm.prank(registry.getGovernance()); + registry.addRollup(IRollup(f)); + vm.etch(f, ""); + vm.expectRevert( - abi.encodeWithSelector( - Errors.GovernanceProposer__InstanceHaveNoCode.selector, address(0xdead) - ) + abi.encodeWithSelector(Errors.GovernanceProposer__InstanceHaveNoCode.selector, address(f)) ); governanceProposer.vote(proposal); } @@ -42,7 +48,7 @@ contract VoteTest is GovernanceProposerBase { modifier givenCanonicalRollupHoldCode() { validatorSelection = new Fakerollup(); vm.prank(registry.getGovernance()); - registry.upgrade(address(validatorSelection)); + registry.addRollup(IRollup(address(validatorSelection))); // We jump into the future since slot 0, will behave as if already voted in vm.warp(Timestamp.unwrap(validatorSelection.getTimestampForSlot(Slot.wrap(1)))); @@ -146,7 +152,7 @@ contract VoteTest is GovernanceProposerBase { Fakerollup freshInstance = new Fakerollup(); vm.prank(registry.getGovernance()); - registry.upgrade(address(freshInstance)); + registry.addRollup(IRollup(address(freshInstance))); vm.warp(Timestamp.unwrap(freshInstance.getTimestampForSlot(Slot.wrap(1)))); diff --git a/l1-contracts/test/governance/governance/TestPayloads.sol b/l1-contracts/test/governance/governance/TestPayloads.sol index db33d41aa54d..b9e75f35ebbe 100644 --- a/l1-contracts/test/governance/governance/TestPayloads.sol +++ b/l1-contracts/test/governance/governance/TestPayloads.sol @@ -34,10 +34,15 @@ contract CallAssetPayload is IPayload { } } +contract FakeRollup { + function getVersion() external view returns (uint256) { + return uint256(keccak256(abi.encodePacked(bytes("aztec_rollup"), block.chainid, address(this)))); + } +} + contract UpgradePayload is IPayload { IRegistry public immutable REGISTRY; - address public constant NEW_ROLLUP = - address(uint160(uint256(keccak256(bytes("a new fancy rollup built with magic"))))); + address public NEW_ROLLUP = address(new FakeRollup()); constructor(IRegistry _registry) { REGISTRY = _registry; @@ -48,7 +53,7 @@ contract UpgradePayload is IPayload { res[0] = Action({ target: address(REGISTRY), - data: abi.encodeWithSelector(REGISTRY.upgrade.selector, NEW_ROLLUP) + data: abi.encodeWithSelector(REGISTRY.addRollup.selector, NEW_ROLLUP) }); return res; diff --git a/l1-contracts/test/governance/governance/base.t.sol b/l1-contracts/test/governance/governance/base.t.sol index f77cbc8d2e10..21d695eecf90 100644 --- a/l1-contracts/test/governance/governance/base.t.sol +++ b/l1-contracts/test/governance/governance/base.t.sol @@ -37,7 +37,7 @@ contract GovernanceBase is TestBase { function setUp() public virtual { token = IMintableERC20(address(new TestERC20("test", "TEST", address(this)))); - registry = new Registry(address(this)); + registry = new Registry(address(this), token); governanceProposer = new GovernanceProposer(registry, 677, 1000); governance = new Governance(token, address(governanceProposer)); diff --git a/l1-contracts/test/governance/governance/execute.t.sol b/l1-contracts/test/governance/governance/execute.t.sol index 200ef4562bc2..360f1da16515 100644 --- a/l1-contracts/test/governance/governance/execute.t.sol +++ b/l1-contracts/test/governance/governance/execute.t.sol @@ -154,7 +154,7 @@ contract ExecuteTest is GovernanceBase { assertEq(governance.getProposalState(proposalId), DataStructures.ProposalState.Executed); assertEq(proposal.state, DataStructures.ProposalState.Executed); - address rollup = registry.getRollup(); + address rollup = address(registry.getCanonicalRollup()); assertEq(rollup, UpgradePayload(address(proposal.payload)).NEW_ROLLUP()); } } diff --git a/l1-contracts/test/governance/governance/scenarios/lockAndPass.t.sol b/l1-contracts/test/governance/governance/scenarios/lockAndPass.t.sol new file mode 100644 index 000000000000..43c7396e54b9 --- /dev/null +++ b/l1-contracts/test/governance/governance/scenarios/lockAndPass.t.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.27; + +import {IPayload} from "@aztec/governance/interfaces/IPayload.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; +import {GovernanceBase} from "../base.t.sol"; +import {IGovernance} from "@aztec/governance/interfaces/IGovernance.sol"; +import {Timestamp} from "@aztec/core/libraries/TimeLib.sol"; +import {Errors} from "@aztec/governance/libraries/Errors.sol"; +import {DataStructures} from "@aztec/governance/libraries/DataStructures.sol"; +import {UpgradePayload, FakeRollup} from "../TestPayloads.sol"; +import {ProposalLib} from "@aztec/governance/libraries/ProposalLib.sol"; + +contract LockAndPassTest is GovernanceBase { + using ProposalLib for DataStructures.Proposal; + + function setUp() public override { + super.setUp(); + + FakeRollup newRollup = new FakeRollup(); + vm.prank(address(governance)); + registry.addRollup(IRollup(address(newRollup))); + } + + function test_LockVoteAndExecute() external { + DataStructures.Configuration memory config = governance.getConfiguration(); + token.mint(address(this), config.proposeConfig.lockAmount); + + UpgradePayload payload = new UpgradePayload(registry); + assertNotEq(address(payload.NEW_ROLLUP()), address(registry.getCanonicalRollup())); + + token.approve(address(governance), config.proposeConfig.lockAmount); + governance.deposit(address(this), config.proposeConfig.lockAmount); + + proposalId = governance.proposalCount(); + vm.expectEmit(true, true, true, true, address(governance)); + emit IGovernance.Proposed(proposalId, address(payload)); + assertTrue(governance.proposeWithLock(IPayload(address(payload)), address(this))); + + proposal = governance.getProposal(proposalId); + assertEq(address(proposal.payload), address(payload)); + + token.mint(address(this), config.minimumVotes); + token.approve(address(governance), config.minimumVotes); + governance.deposit(address(this), config.minimumVotes); + + vm.warp(Timestamp.unwrap(proposal.pendingThrough()) + 1); + assertEq(governance.getProposalState(proposalId), DataStructures.ProposalState.Active); + + vm.prank(address(this)); + governance.vote(proposalId, config.minimumVotes, true); + + vm.warp(Timestamp.unwrap(proposal.activeThrough()) + 1); + assertEq(governance.getProposalState(proposalId), DataStructures.ProposalState.Queued); + + vm.warp(Timestamp.unwrap(proposal.queuedThrough()) + 1); + assertEq(governance.getProposalState(proposalId), DataStructures.ProposalState.Executable); + + assertNotEq(address(registry.getCanonicalRollup()), address(payload.NEW_ROLLUP())); + governance.execute(proposalId); + assertEq(address(registry.getCanonicalRollup()), address(payload.NEW_ROLLUP())); + + assertEq(governance.getProposalState(proposalId), DataStructures.ProposalState.Executed); + assertEq(registry.numberOfVersions(), 2); + } +} diff --git a/l1-contracts/test/governance/registry/Base.t.sol b/l1-contracts/test/governance/registry/Base.t.sol index e76ef145355e..f56f62d6402b 100644 --- a/l1-contracts/test/governance/registry/Base.t.sol +++ b/l1-contracts/test/governance/registry/Base.t.sol @@ -4,11 +4,19 @@ pragma solidity >=0.8.27; import {Test} from "forge-std/Test.sol"; import {Registry} from "@aztec/governance/Registry.sol"; +import {TestERC20} from "@aztec/mock/TestERC20.sol"; + +contract FakeRollup { + function getVersion() external view returns (uint256) { + return uint256(keccak256(abi.encodePacked(bytes("aztec_rollup"), block.chainid, address(this)))); + } +} contract RegistryBase is Test { Registry internal registry; - function setUp() public { - registry = new Registry(address(this)); + function setUp() public virtual { + TestERC20 asset = new TestERC20("test", "TEST", address(this)); + registry = new Registry(address(this), asset); } } diff --git a/l1-contracts/test/governance/registry/upgrade.t.sol b/l1-contracts/test/governance/registry/addRollup.t.sol similarity index 53% rename from l1-contracts/test/governance/registry/upgrade.t.sol rename to l1-contracts/test/governance/registry/addRollup.t.sol index 534465031b62..5b135a82003f 100644 --- a/l1-contracts/test/governance/registry/upgrade.t.sol +++ b/l1-contracts/test/governance/registry/addRollup.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.27; -import {RegistryBase} from "./Base.t.sol"; +import {RegistryBase, FakeRollup} from "./Base.t.sol"; import {Ownable} from "@oz/access/Ownable.sol"; @@ -9,13 +9,19 @@ import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; import {Errors} from "@aztec/governance/libraries/Errors.sol"; import {DataStructures} from "@aztec/governance/libraries/DataStructures.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; + contract UpgradeTest is RegistryBase { + function setUp() public override { + super.setUp(); + } + function test_RevertWhen_CallerIsNotOwner(address _caller) external { // it should revert vm.assume(_caller != address(this)); vm.prank(_caller); vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, _caller)); - registry.upgrade(address(uint160(uint256(bytes32("new instance"))))); + registry.addRollup(IRollup(address(uint160(uint256(bytes32("new instance")))))); } modifier whenCallerIsOwner() { @@ -24,35 +30,29 @@ contract UpgradeTest is RegistryBase { function test_RevertWhen_RollupAlreadyInSet() external whenCallerIsOwner { // it should revert - address rollup = registry.getRollup(); + + registry.addRollup(IRollup(address(new FakeRollup()))); + address rollup = address(registry.getCanonicalRollup()); vm.expectRevert( abi.encodeWithSelector(Errors.Registry__RollupAlreadyRegistered.selector, rollup) ); - registry.upgrade(rollup); + registry.addRollup(IRollup(rollup)); } - function test_WhenRollupNotAlreadyInSet(address _rollup) external whenCallerIsOwner { + function test_WhenRollupNotAlreadyInSet() external whenCallerIsOwner { // it should add the rollup to state // it should emit a {InstanceAdded} event - vm.assume(_rollup != address(0xdead)); - { - DataStructures.RegistrySnapshot memory snapshotBefore = registry.getCurrentSnapshot(); - assertEq(snapshotBefore.blockNumber, block.number); - assertEq(snapshotBefore.rollup, address(0xdead)); - assertEq(registry.numberOfVersions(), 1); - } + IRollup newRollup = IRollup(address(new FakeRollup())); + uint256 version = newRollup.getVersion(); vm.expectEmit(true, true, false, false, address(registry)); - emit IRegistry.InstanceAdded(_rollup, 1); - registry.upgrade(_rollup); + emit IRegistry.InstanceAdded(address(newRollup), version); + registry.addRollup(newRollup); - assertEq(registry.numberOfVersions(), 2); + assertEq(registry.numberOfVersions(), 1); - DataStructures.RegistrySnapshot memory snapshot = registry.getCurrentSnapshot(); - assertEq(snapshot.blockNumber, block.number); - assertGt(snapshot.blockNumber, 0); - assertEq(snapshot.rollup, _rollup); + assertEq(address(registry.getRollup(version)), address(newRollup)); } } diff --git a/l1-contracts/test/governance/registry/upgrade.tree b/l1-contracts/test/governance/registry/addRollup.tree similarity index 83% rename from l1-contracts/test/governance/registry/upgrade.tree rename to l1-contracts/test/governance/registry/addRollup.tree index ac72d6892c35..062144f65a75 100644 --- a/l1-contracts/test/governance/registry/upgrade.tree +++ b/l1-contracts/test/governance/registry/addRollup.tree @@ -6,4 +6,4 @@ UpgradeTest │ └── it should revert └── when rollup not already in set ├── it should add the rollup to state - └── it should emit a {InstanceAdded} event \ No newline at end of file + └── it should emit a {InstanceAdded} event diff --git a/l1-contracts/test/governance/registry/getCanonicalRollup.t.sol b/l1-contracts/test/governance/registry/getCanonicalRollup.t.sol new file mode 100644 index 000000000000..cfc1d5b1bee1 --- /dev/null +++ b/l1-contracts/test/governance/registry/getCanonicalRollup.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.27; + +import {RegistryBase, FakeRollup} from "./Base.t.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; +import {Errors} from "@aztec/governance/libraries/Errors.sol"; + +contract GetRollupTest is RegistryBase { + function test_GivenNoListedRollups() external { + // it should revert + vm.expectRevert(abi.encodeWithSelector(Errors.Registry__NoRollupsRegistered.selector)); + registry.getCanonicalRollup(); + } + + function test_GivenMultipleListedRollups() external { + // it should return the newest + + address rollup = address(new FakeRollup()); + registry.addRollup(IRollup(rollup)); + assertEq(address(registry.getCanonicalRollup()), rollup); + + address rollup2 = address(new FakeRollup()); + registry.addRollup(IRollup(rollup2)); + assertEq(address(registry.getCanonicalRollup()), rollup2); + } +} diff --git a/l1-contracts/test/governance/registry/getCanonicalRollup.tree b/l1-contracts/test/governance/registry/getCanonicalRollup.tree new file mode 100644 index 000000000000..2ac0c51b71cf --- /dev/null +++ b/l1-contracts/test/governance/registry/getCanonicalRollup.tree @@ -0,0 +1,5 @@ +GetCanonicalRollupTest +├── given no listed rollups +│ └── it should revert +└── given multiple listed rollups + └── it should return the newest diff --git a/l1-contracts/test/governance/registry/getCurrentSnapshotTest.t.sol b/l1-contracts/test/governance/registry/getCurrentSnapshotTest.t.sol deleted file mode 100644 index bd7d752338a1..000000000000 --- a/l1-contracts/test/governance/registry/getCurrentSnapshotTest.t.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.27; - -import {RegistryBase} from "./Base.t.sol"; - -import {DataStructures} from "@aztec/governance/libraries/DataStructures.sol"; - -contract GetCurrentSnapshotTest is RegistryBase { - function test_GivenOneListedRollup() external view { - // it should return the newest - DataStructures.RegistrySnapshot memory snapshot = registry.getCurrentSnapshot(); - assertEq(snapshot.blockNumber, block.number); - assertEq(snapshot.rollup, address(0xdead)); - assertEq(registry.numberOfVersions(), 1); - } - - function test_GivenMultipleListedRollups() external { - // it should return the newest - address rollup = address(uint160(uint256(bytes32("new instance")))); - registry.upgrade(rollup); - - DataStructures.RegistrySnapshot memory snapshot = registry.getCurrentSnapshot(); - assertEq(snapshot.blockNumber, block.number); - assertGt(snapshot.blockNumber, 0); - assertEq(snapshot.rollup, rollup); - } -} diff --git a/l1-contracts/test/governance/registry/getCurrentSnapshotTest.tree b/l1-contracts/test/governance/registry/getCurrentSnapshotTest.tree deleted file mode 100644 index 0b2a3b826a78..000000000000 --- a/l1-contracts/test/governance/registry/getCurrentSnapshotTest.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetCurrentSnapshotTest -├── given one listed rollup -│ └── it should return the newest -└── given multiple listed rollups - └── it should return the newest \ No newline at end of file diff --git a/l1-contracts/test/governance/registry/getRollup.t.sol b/l1-contracts/test/governance/registry/getRollup.t.sol deleted file mode 100644 index bc95b03465e9..000000000000 --- a/l1-contracts/test/governance/registry/getRollup.t.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.27; - -import {RegistryBase} from "./Base.t.sol"; - -contract GetRollupTest is RegistryBase { - function test_GivenOneListedRollup() external view { - // it should return the newest - assertEq(registry.getRollup(), address(0xdead)); - } - - function test_GivenMultipleListedRollups() external { - // it should return the newest - address rollup = address(uint160(uint256(bytes32("new instance")))); - registry.upgrade(rollup); - assertEq(registry.getRollup(), rollup); - } -} diff --git a/l1-contracts/test/governance/registry/getRollup.tree b/l1-contracts/test/governance/registry/getRollup.tree deleted file mode 100644 index 6064511d509a..000000000000 --- a/l1-contracts/test/governance/registry/getRollup.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetRollupTest -├── given one listed rollup -│ └── it should return the newest -└── given multiple listed rollups - └── it should return the newest \ No newline at end of file diff --git a/l1-contracts/test/governance/registry/getSnapshot.t.sol b/l1-contracts/test/governance/registry/getSnapshot.t.sol deleted file mode 100644 index 0cf111ec5305..000000000000 --- a/l1-contracts/test/governance/registry/getSnapshot.t.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.27; - -import {RegistryBase} from "./Base.t.sol"; - -import {DataStructures} from "@aztec/governance/libraries/DataStructures.sol"; - -contract GetSnapshotTest is RegistryBase { - modifier givenMultipleListedRollups() { - _; - } - - function test_When_versionExists() external view givenMultipleListedRollups { - // it should return the snapshot - - DataStructures.RegistrySnapshot memory snapshot = registry.getSnapshot(0); - assertEq(snapshot.blockNumber, block.number); - assertEq(snapshot.rollup, address(0xdead)); - assertEq(registry.numberOfVersions(), 1); - } - - function test_When_versionDoesNotExists(uint256 _version) - external - view - givenMultipleListedRollups - { - // it should return empty snapshot - - uint256 version = bound(_version, 1, type(uint256).max); - - DataStructures.RegistrySnapshot memory snapshot = registry.getSnapshot(version); - assertEq(snapshot.blockNumber, 0); - assertEq(snapshot.rollup, address(0)); - assertEq(registry.numberOfVersions(), 1); - } -} diff --git a/l1-contracts/test/governance/registry/getSnapshot.tree b/l1-contracts/test/governance/registry/getSnapshot.tree deleted file mode 100644 index ed095a9473e9..000000000000 --- a/l1-contracts/test/governance/registry/getSnapshot.tree +++ /dev/null @@ -1,6 +0,0 @@ -GetSnapshotTest -└── given multiple listed rollups - ├── when _version exists - │ └── it should return the snapshot - └── when _version does not exists - └── it should return empty snapshot \ No newline at end of file diff --git a/l1-contracts/test/governance/registry/getVersionFor.t.sol b/l1-contracts/test/governance/registry/getVersionFor.t.sol deleted file mode 100644 index 51a05a2f7819..000000000000 --- a/l1-contracts/test/governance/registry/getVersionFor.t.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.27; - -import {RegistryBase} from "./Base.t.sol"; -import {Errors} from "@aztec/governance/libraries/Errors.sol"; - -contract GetVersionForTest is RegistryBase { - address internal rollup; - - modifier givenNoAdditionalListedRollups() { - _; - } - - function test_When_rollupIs0xdead() external view givenNoAdditionalListedRollups { - // it should return 0 - assertEq(registry.getVersionFor(address(0xdead)), 0); - } - - function test_RevertWhen__rollupNot0xdead(address _rollup) - external - givenNoAdditionalListedRollups - { - // it should revert - vm.assume(_rollup != address(0xdead)); - vm.expectRevert(abi.encodeWithSelector(Errors.Registry__RollupNotRegistered.selector, _rollup)); - registry.getVersionFor(_rollup); - } - - modifier givenMultipleListedRollups() { - rollup = address(0xbeef); - registry.upgrade(rollup); - _; - } - - function test_When_rollupIsListed() external givenMultipleListedRollups { - // it should return the rollup version - assertEq(registry.getVersionFor(address(0xdead)), 0); - assertEq(registry.getVersionFor(address(0xbeef)), 1); - } - - function test_RevertWhen__rollupIsNotListed(address _rollup) external givenMultipleListedRollups { - // it should revert - vm.assume(_rollup != address(0xdead) && _rollup != address(0xbeef)); - vm.expectRevert(abi.encodeWithSelector(Errors.Registry__RollupNotRegistered.selector, _rollup)); - registry.getVersionFor(_rollup); - } -} diff --git a/l1-contracts/test/governance/registry/getVersionFor.tree b/l1-contracts/test/governance/registry/getVersionFor.tree deleted file mode 100644 index 25e2d07b3aac..000000000000 --- a/l1-contracts/test/governance/registry/getVersionFor.tree +++ /dev/null @@ -1,11 +0,0 @@ -GetVersionForTest -├── given no additional listed rollups -│ ├── when _rollup is 0xdead -│ │ └── it should return 0 -│ └── when _rollup not 0xdead -│ └── it should revert -└── given multiple listed rollups - ├── when _rollup is listed - │ └── it should return the rollup version - └── when _rollup is not listed - └── it should revert \ No newline at end of file diff --git a/l1-contracts/test/governance/registry/isRollupRegistered.t.sol b/l1-contracts/test/governance/registry/isRollupRegistered.t.sol deleted file mode 100644 index 3f6d76f575db..000000000000 --- a/l1-contracts/test/governance/registry/isRollupRegistered.t.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.27; - -import {RegistryBase} from "./Base.t.sol"; - -contract IsRollupRegisteredTest is RegistryBase { - address internal rollup; - - modifier givenNoAdditionalListedRollups() { - _; - } - - function test_When_rollupIs0xdead() external view givenNoAdditionalListedRollups { - // it should return true - assertTrue(registry.isRollupRegistered(address(0xdead))); - } - - function test_When_rollupNot0xdead(address _rollup) external view givenNoAdditionalListedRollups { - // it should return false - vm.assume(_rollup != address(0xdead)); - assertFalse(registry.isRollupRegistered(_rollup)); - } - - modifier givenMultipleListedRollups() { - rollup = address(0xbeef); - registry.upgrade(rollup); - _; - } - - function test_When_rollupIsListed() external givenMultipleListedRollups { - // it should return true - assertTrue(registry.isRollupRegistered(address(0xdead))); - assertTrue(registry.isRollupRegistered(address(0xbeef))); - } - - function test_When_rollupIsNotListed(address _rollup) external givenMultipleListedRollups { - // it should return false - vm.assume(_rollup != address(0xdead) && _rollup != address(0xbeef)); - assertFalse(registry.isRollupRegistered(_rollup)); - } -} diff --git a/l1-contracts/test/governance/registry/isRollupRegistered.tree b/l1-contracts/test/governance/registry/isRollupRegistered.tree deleted file mode 100644 index b5b063720763..000000000000 --- a/l1-contracts/test/governance/registry/isRollupRegistered.tree +++ /dev/null @@ -1,11 +0,0 @@ -IsRollupRegisteredTest -├── given no additional listed rollups -│ ├── when _rollup is 0xdead -│ │ └── it should return true -│ └── when _rollup not 0xdead -│ └── it should return false -└── given multiple listed rollups - ├── when _rollup is listed - │ └── it should return true - └── when _rollup is not listed - └── it should return false \ No newline at end of file diff --git a/l1-contracts/test/governance/reward-distributor/Base.t.sol b/l1-contracts/test/governance/reward-distributor/Base.t.sol index 4c6014d5a2ce..f09be7d939e1 100644 --- a/l1-contracts/test/governance/reward-distributor/Base.t.sol +++ b/l1-contracts/test/governance/reward-distributor/Base.t.sol @@ -9,6 +9,13 @@ import {Registry} from "@aztec/governance/Registry.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; import {TestERC20} from "@aztec/mock/TestERC20.sol"; +import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; + +contract FakeRollup { + function getVersion() external view returns (uint256) { + return uint256(keccak256(abi.encodePacked(bytes("aztec_rollup"), block.chainid, address(this)))); + } +} contract RewardDistributorBase is Test { IMintableERC20 internal token; @@ -17,7 +24,10 @@ contract RewardDistributorBase is Test { function setUp() public { token = IMintableERC20(address(new TestERC20("test", "TEST", address(this)))); - registry = new Registry(address(this)); - rewardDistributor = new RewardDistributor(token, registry, address(this)); + registry = new Registry(address(this), token); + + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); + + registry.addRollup(IRollup(address(new FakeRollup()))); } } diff --git a/l1-contracts/test/governance/reward-distributor/claim.t.sol b/l1-contracts/test/governance/reward-distributor/claim.t.sol index f4f964acbc4e..9caffcbef647 100644 --- a/l1-contracts/test/governance/reward-distributor/claim.t.sol +++ b/l1-contracts/test/governance/reward-distributor/claim.t.sol @@ -10,19 +10,18 @@ contract ClaimTest is RewardDistributorBase { function test_WhenCallerIsNotCanonical(address _caller) external { // it reverts - vm.assume(_caller != address(0xdead)); + address canonical = address(registry.getCanonicalRollup()); + vm.assume(_caller != canonical); vm.expectRevert( - abi.encodeWithSelector( - Errors.RewardDistributor__InvalidCaller.selector, _caller, address(0xdead) - ) + abi.encodeWithSelector(Errors.RewardDistributor__InvalidCaller.selector, _caller, canonical) ); vm.prank(_caller); rewardDistributor.claim(_caller); } modifier whenCallerIsCanonical() { - caller = address(0xdead); + caller = address(registry.getCanonicalRollup()); _; } diff --git a/l1-contracts/test/governance/reward-distributor/updateRegistry.t.sol b/l1-contracts/test/governance/reward-distributor/updateRegistry.t.sol deleted file mode 100644 index 0d278a2d859d..000000000000 --- a/l1-contracts/test/governance/reward-distributor/updateRegistry.t.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.27; - -import {RewardDistributorBase} from "./Base.t.sol"; -import {Ownable} from "@oz/access/Ownable.sol"; - -import {Registry} from "@aztec/governance/Registry.sol"; -import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; -import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol"; - -contract UpdateRegistryTest is RewardDistributorBase { - address internal caller; - - function test_WhenCallerIsNotOwner(address _caller) external { - // it reverts - vm.assume(_caller != rewardDistributor.owner()); - - vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, _caller)); - vm.prank(_caller); - rewardDistributor.updateRegistry(IRegistry(address(0xdead))); - } - - function test_WhenCallerIsOwner() external { - // it updates the registry - // it emits a {RegistryUpdated} event - - Registry registry = new Registry(address(this)); - registry.upgrade(address(0xbeef)); - - IRegistry oldRegistry = rewardDistributor.registry(); - address oldCanonical = rewardDistributor.canonicalRollup(); - - vm.prank(rewardDistributor.owner()); - vm.expectEmit(true, true, false, true, address(rewardDistributor)); - emit IRewardDistributor.RegistryUpdated(registry); - rewardDistributor.updateRegistry(registry); - - assertEq(address(rewardDistributor.registry()), address(registry)); - assertNotEq(address(oldRegistry), address(registry)); - assertEq(rewardDistributor.canonicalRollup(), address(0xbeef)); - assertNotEq(oldCanonical, address(0xbeef)); - } -} diff --git a/l1-contracts/test/governance/reward-distributor/updateRegistry.tree b/l1-contracts/test/governance/reward-distributor/updateRegistry.tree deleted file mode 100644 index 596aea57c19a..000000000000 --- a/l1-contracts/test/governance/reward-distributor/updateRegistry.tree +++ /dev/null @@ -1,6 +0,0 @@ -UpdateRegistryTest -├── when caller is not owner -│ └── it reverts -└── when caller is owner - ├── it updates the registry - └── it emits a {RegistryUpdated} event \ No newline at end of file diff --git a/l1-contracts/test/governance/scenario/RegisterNewRollupVersionPayload.sol b/l1-contracts/test/governance/scenario/RegisterNewRollupVersionPayload.sol index abde0a0ef8fb..5b4c4ab0af52 100644 --- a/l1-contracts/test/governance/scenario/RegisterNewRollupVersionPayload.sol +++ b/l1-contracts/test/governance/scenario/RegisterNewRollupVersionPayload.sol @@ -23,7 +23,7 @@ contract RegisterNewRollupVersionPayload is IPayload { res[0] = Action({ target: address(REGISTRY), - data: abi.encodeWithSelector(IRegistry.upgrade.selector, ROLLUP) + data: abi.encodeWithSelector(IRegistry.addRollup.selector, ROLLUP) }); return res; diff --git a/l1-contracts/test/governance/scenario/UpgradeGovernanceProposerTest.t.sol b/l1-contracts/test/governance/scenario/UpgradeGovernanceProposerTest.t.sol index b7a6cff8bb8d..08a4dd36f4e8 100644 --- a/l1-contracts/test/governance/scenario/UpgradeGovernanceProposerTest.t.sol +++ b/l1-contracts/test/governance/scenario/UpgradeGovernanceProposerTest.t.sol @@ -17,7 +17,7 @@ import {ProposalLib} from "@aztec/governance/libraries/ProposalLib.sol"; import {Errors} from "@aztec/governance/libraries/Errors.sol"; import {NewGovernanceProposerPayload} from "./NewGovernanceProposerPayload.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; -import {CheatDepositArgs} from "@aztec/core/interfaces/IRollup.sol"; +import {IRollup, CheatDepositArgs} from "@aztec/core/interfaces/IRollup.sol"; import {TestConstants} from "../../harnesses/TestConstants.sol"; /** @@ -47,7 +47,7 @@ contract UpgradeGovernanceProposerTest is TestBase { function setUp() external { token = IMintableERC20(address(new TestERC20("test", "TEST", address(this)))); - registry = new Registry(address(this)); + registry = new Registry(address(this), token); governanceProposer = new GovernanceProposer(registry, 7, 10); governance = new Governance(token, address(governanceProposer)); @@ -66,9 +66,10 @@ contract UpgradeGovernanceProposerTest is TestBase { }); } - RewardDistributor rewardDistributor = new RewardDistributor(token, registry, address(this)); + RewardDistributor rewardDistributor = + RewardDistributor(address(registry.getRewardDistributor())); rollup = new Rollup( - new MockFeeJuicePortal(), + token, rewardDistributor, token, address(this), @@ -80,8 +81,8 @@ contract UpgradeGovernanceProposerTest is TestBase { token.approve(address(rollup), TestConstants.AZTEC_MINIMUM_STAKE * VALIDATOR_COUNT); rollup.cheat__InitialiseValidatorSet(initialValidators); - registry.upgrade(address(rollup)); - + registry.addRollup(IRollup(address(rollup))); + registry.updateGovernance(address(governance)); registry.transferOwnership(address(governance)); } diff --git a/l1-contracts/test/governance/scenario/slashing/Slashing.t.sol b/l1-contracts/test/governance/scenario/slashing/Slashing.t.sol index f776111968fb..7b8fe2d95c57 100644 --- a/l1-contracts/test/governance/scenario/slashing/Slashing.t.sol +++ b/l1-contracts/test/governance/scenario/slashing/Slashing.t.sol @@ -51,10 +51,10 @@ contract SlashingScenario is TestBase { } testERC20 = new TestERC20("test", "TEST", address(this)); - Registry registry = new Registry(address(this)); - rewardDistributor = new RewardDistributor(testERC20, registry, address(this)); + Registry registry = new Registry(address(this), testERC20); + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); rollup = new Rollup({ - _fpcJuicePortal: new MockFeeJuicePortal(), + _feeAsset: testERC20, _rewardDistributor: rewardDistributor, _stakingAsset: testERC20, _governance: address(this), diff --git a/l1-contracts/test/harnesses/InboxHarness.sol b/l1-contracts/test/harnesses/InboxHarness.sol index a9e1779d6d3c..41bc14a92fa5 100644 --- a/l1-contracts/test/harnesses/InboxHarness.sol +++ b/l1-contracts/test/harnesses/InboxHarness.sol @@ -10,7 +10,7 @@ import {FrontierLib} from "@aztec/core/libraries/crypto/FrontierLib.sol"; contract InboxHarness is Inbox { using FrontierLib for FrontierLib.Tree; - constructor(address _rollup, uint256 _height) Inbox(_rollup, _height) {} + constructor(address _rollup, uint256 _version, uint256 _height) Inbox(_rollup, _version, _height) {} function getSize() external view returns (uint256) { return SIZE; diff --git a/l1-contracts/test/ignition.t.sol b/l1-contracts/test/ignition.t.sol index df670a7a32ae..86a1fbf7efb9 100644 --- a/l1-contracts/test/ignition.t.sol +++ b/l1-contracts/test/ignition.t.sol @@ -22,7 +22,7 @@ import {Strings} from "@oz/utils/Strings.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import {RollupBase, IInstance} from "./base/RollupBase.sol"; -import {RollupConfigInput} from "@aztec/core/interfaces/IRollup.sol"; +import {IRollup, RollupConfigInput} from "@aztec/core/interfaces/IRollup.sol"; // solhint-disable comprehensive-interface @@ -70,14 +70,7 @@ contract IgnitionTest is RollupBase { vm.warp(initialTime); } - registry = new Registry(address(this)); - feeJuicePortal = new FeeJuicePortal( - address(registry), address(testERC20), bytes32(Constants.FEE_JUICE_ADDRESS) - ); - testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); - feeJuicePortal.initialize(); - rewardDistributor = new RewardDistributor(testERC20, registry, address(this)); - testERC20.mint(address(rewardDistributor), 1e6 ether); + registry = new Registry(address(this), testERC20); RollupConfigInput memory rollupConfigInput = TestConstants.getRollupConfigInput(); @@ -89,7 +82,7 @@ contract IgnitionTest is RollupBase { rollup = IInstance( address( new Rollup( - feeJuicePortal, + testERC20, rewardDistributor, testERC20, address(this), @@ -99,7 +92,13 @@ contract IgnitionTest is RollupBase { ) ); - registry.upgrade(address(rollup)); + feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal())); + testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); + feeJuicePortal.initialize(); + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); + testERC20.mint(address(rewardDistributor), 1e6 ether); + + registry.addRollup(IRollup(address(rollup))); _; } diff --git a/l1-contracts/test/portals/TokenPortal.sol b/l1-contracts/test/portals/TokenPortal.sol index 0c89cc05664b..9026a43cf375 100644 --- a/l1-contracts/test/portals/TokenPortal.sol +++ b/l1-contracts/test/portals/TokenPortal.sol @@ -28,6 +28,11 @@ contract TokenPortal { IERC20 public underlying; bytes32 public l2Bridge; + IRollup public rollup; + IOutbox public outbox; + IInbox public inbox; + uint256 public rollupVersion; + /** * @notice Initialize the portal * @param _registry - The registry address @@ -39,6 +44,11 @@ contract TokenPortal { registry = IRegistry(_registry); underlying = IERC20(_underlying); l2Bridge = _l2Bridge; + + rollup = IRollup(registry.getCanonicalRollup()); + outbox = rollup.getOutbox(); + inbox = rollup.getInbox(); + rollupVersion = rollup.getVersion(); } // docs:end:init @@ -56,8 +66,7 @@ contract TokenPortal { // docs:end:deposit_public { // Preamble - IInbox inbox = IRollup(registry.getRollup()).getInbox(); - DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2Bridge, 1); + DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2Bridge, rollupVersion); // Hash the message content to be reconstructed in the receiving contract // The purpose of including the function selector is to make the message unique to that specific call. Note that @@ -90,8 +99,7 @@ contract TokenPortal { // docs:end:deposit_private { // Preamble - IInbox inbox = IRollup(registry.getRollup()).getInbox(); - DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2Bridge, 1); + DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2Bridge, rollupVersion); // Hash the message content to be reconstructed in the receiving contract - the signature below does not correspond // to a real function. It's just an identifier of an action. @@ -134,7 +142,7 @@ contract TokenPortal { // The purpose of including the function selector is to make the message unique to that specific call. Note that // it has nothing to do with calling the function. DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2Bridge, 1), + sender: DataStructures.L2Actor(l2Bridge, rollupVersion), recipient: DataStructures.L1Actor(address(this), block.chainid), content: Hash.sha256ToField( abi.encodeWithSignature( @@ -146,8 +154,6 @@ contract TokenPortal { ) }); - IOutbox outbox = IRollup(registry.getRollup()).getOutbox(); - outbox.consume(message, _l2BlockNumber, _leafIndex, _path); underlying.transfer(_recipient, _amount); diff --git a/l1-contracts/test/portals/TokenPortal.t.sol b/l1-contracts/test/portals/TokenPortal.t.sol index ff4c2d963a7d..b772bd7b2c98 100644 --- a/l1-contracts/test/portals/TokenPortal.t.sol +++ b/l1-contracts/test/portals/TokenPortal.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.27; import "forge-std/Test.sol"; // Rollup Processor -import {Rollup} from "@aztec/core/Rollup.sol"; +import {IRollup, Rollup} from "@aztec/core/Rollup.sol"; import {Constants} from "@aztec/core/libraries/ConstantsGen.sol"; import {Registry} from "@aztec/governance/Registry.sol"; import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; @@ -60,11 +60,11 @@ contract TokenPortalTest is Test { uint256 internal l2BlockNumber = 69; function setUp() public { - registry = new Registry(address(this)); testERC20 = new TestERC20("test", "TEST", address(this)); - rewardDistributor = new RewardDistributor(testERC20, registry, address(this)); + registry = new Registry(address(this), testERC20); + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); rollup = new Rollup( - new MockFeeJuicePortal(), + testERC20, rewardDistributor, testERC20, address(this), @@ -74,7 +74,7 @@ contract TokenPortalTest is Test { inbox = rollup.getInbox(); outbox = rollup.getOutbox(); - registry.upgrade(address(rollup)); + registry.addRollup(IRollup(address(rollup))); tokenPortal = new TokenPortal(); tokenPortal.initialize(address(registry), address(testERC20), l2TokenAddress); @@ -95,7 +95,7 @@ contract TokenPortalTest is Test { // it has nothing to do with calling the function. return DataStructures.L1ToL2Msg({ sender: DataStructures.L1Actor(address(tokenPortal), block.chainid), - recipient: DataStructures.L2Actor(l2TokenAddress, 1), + recipient: DataStructures.L2Actor(l2TokenAddress, rollup.getVersion()), content: Hash.sha256ToField(abi.encodeWithSignature("mint_to_private(uint256)", amount)), secretHash: secretHashForL2MessageConsumption, index: _index @@ -111,7 +111,7 @@ contract TokenPortalTest is Test { // it has nothing to do with calling the function. return DataStructures.L1ToL2Msg({ sender: DataStructures.L1Actor(address(tokenPortal), block.chainid), - recipient: DataStructures.L2Actor(l2TokenAddress, 1), + recipient: DataStructures.L2Actor(l2TokenAddress, rollup.getVersion()), content: Hash.sha256ToField( abi.encodeWithSignature("mint_to_public(bytes32,uint256)", to, amount) ), @@ -182,7 +182,7 @@ contract TokenPortalTest is Test { // it has nothing to do with calling the function. bytes32 l2ToL1Message = Hash.sha256ToField( DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor({actor: l2TokenAddress, version: 1}), + sender: DataStructures.L2Actor({actor: l2TokenAddress, version: rollup.getVersion()}), recipient: DataStructures.L1Actor({actor: address(tokenPortal), chainId: block.chainid}), content: Hash.sha256ToField( abi.encodeWithSignature( diff --git a/l1-contracts/test/portals/UniswapPortal.sol b/l1-contracts/test/portals/UniswapPortal.sol index cd169a5fad4a..5aabffc4d029 100644 --- a/l1-contracts/test/portals/UniswapPortal.sol +++ b/l1-contracts/test/portals/UniswapPortal.sol @@ -26,10 +26,17 @@ contract UniswapPortal { IRegistry public registry; bytes32 public l2UniswapAddress; + IRollup public rollup; + IOutbox public outbox; + uint256 public rollupVersion; function initialize(address _registry, bytes32 _l2UniswapAddress) external { registry = IRegistry(_registry); l2UniswapAddress = _l2UniswapAddress; + + rollup = IRollup(registry.getCanonicalRollup()); + outbox = rollup.getOutbox(); + rollupVersion = rollup.getVersion(); } // Using a struct here to avoid stack too deep errors @@ -106,11 +113,9 @@ contract UniswapPortal { // Consume the message from the outbox { - IOutbox outbox = IRollup(registry.getRollup()).getOutbox(); - outbox.consume( DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2UniswapAddress, 1), + sender: DataStructures.L2Actor(l2UniswapAddress, rollupVersion), recipient: DataStructures.L1Actor(address(this), block.chainid), content: vars.contentHash }), @@ -211,11 +216,9 @@ contract UniswapPortal { // Consume the message from the outbox { - IOutbox outbox = IRollup(registry.getRollup()).getOutbox(); - outbox.consume( DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2UniswapAddress, 1), + sender: DataStructures.L2Actor(l2UniswapAddress, rollupVersion), recipient: DataStructures.L1Actor(address(this), block.chainid), content: vars.contentHash }), diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index b321f8f9748f..058f6f18bee9 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.27; import "forge-std/Test.sol"; // Rollup Processor -import {Rollup} from "@aztec/core/Rollup.sol"; +import {IRollup, Rollup} from "@aztec/core/Rollup.sol"; import {TestConstants} from "../harnesses/TestConstants.sol"; import {Registry} from "@aztec/governance/Registry.sol"; import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; @@ -24,6 +24,8 @@ import {MockFeeJuicePortal} from "@aztec/mock/MockFeeJuicePortal.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; import {stdStorage, StdStorage} from "forge-std/Test.sol"; +import {TestERC20} from "@aztec/mock/TestERC20.sol"; + contract UniswapPortalTest is Test { using stdStorage for StdStorage; using Hash for DataStructures.L2ToL1Msg; @@ -55,17 +57,20 @@ contract UniswapPortalTest is Test { uint256 forkId = vm.createFork(vm.rpcUrl("mainnet_fork")); vm.selectFork(forkId); - registry = new Registry(address(this)); - RewardDistributor rewardDistributor = new RewardDistributor(DAI, registry, address(this)); + TestERC20 testERC20 = new TestERC20("test", "TEST", address(this)); + + registry = new Registry(address(this), testERC20); + RewardDistributor rewardDistributor = + RewardDistributor(address(registry.getRewardDistributor())); rollup = new Rollup( - new MockFeeJuicePortal(), + testERC20, rewardDistributor, - DAI, + testERC20, address(this), TestConstants.getGenesisState(), TestConstants.getRollupConfigInput() ); - registry.upgrade(address(rollup)); + registry.addRollup(IRollup(address(rollup))); daiTokenPortal = new TokenPortal(); daiTokenPortal.initialize(address(registry), address(DAI), l2TokenAddress); @@ -102,7 +107,7 @@ contract UniswapPortalTest is Test { // The purpose of including the function selector is to make the message unique to that specific call. Note that // it has nothing to do with calling the function. DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2TokenAddress, 1), + sender: DataStructures.L2Actor(l2TokenAddress, rollup.getVersion()), recipient: DataStructures.L1Actor(address(daiTokenPortal), block.chainid), content: Hash.sha256ToField( abi.encodeWithSignature("withdraw(address,uint256,address)", _recipient, amount, _caller) @@ -126,7 +131,7 @@ contract UniswapPortalTest is Test { // The purpose of including the function selector is to make the message unique to that specific call. Note that // it has nothing to do with calling the function. DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2UniswapAddress, 1), + sender: DataStructures.L2Actor(l2UniswapAddress, rollup.getVersion()), recipient: DataStructures.L1Actor(address(uniswapPortal), block.chainid), content: Hash.sha256ToField( abi.encodeWithSignature( @@ -155,7 +160,7 @@ contract UniswapPortalTest is Test { // The purpose of including the function selector is to make the message unique to that specific call. Note that // it has nothing to do with calling the function. DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2UniswapAddress, 1), + sender: DataStructures.L2Actor(l2UniswapAddress, rollup.getVersion()), recipient: DataStructures.L1Actor(address(uniswapPortal), block.chainid), content: Hash.sha256ToField( abi.encodeWithSignature( diff --git a/l1-contracts/test/validator-selection/ValidatorSelection.t.sol b/l1-contracts/test/validator-selection/ValidatorSelection.t.sol index 0b8d77545d3f..4c9fefea708e 100644 --- a/l1-contracts/test/validator-selection/ValidatorSelection.t.sol +++ b/l1-contracts/test/validator-selection/ValidatorSelection.t.sol @@ -22,7 +22,7 @@ import {ProposeArgs, OracleInput, ProposeLib} from "@aztec/core/libraries/rollup import {TestConstants} from "../harnesses/TestConstants.sol"; import {CheatDepositArgs} from "@aztec/core/interfaces/IRollup.sol"; -import {Slot, Epoch, EpochLib} from "@aztec/core/libraries/TimeLib.sol"; +import {Slot, Epoch, EpochLib, Timestamp} from "@aztec/core/libraries/TimeLib.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; import {SlashFactory} from "@aztec/periphery/SlashFactory.sol"; @@ -94,10 +94,10 @@ contract ValidatorSelectionTest is DecoderBase { } testERC20 = new TestERC20("test", "TEST", address(this)); - Registry registry = new Registry(address(this)); - rewardDistributor = new RewardDistributor(testERC20, registry, address(this)); + Registry registry = new Registry(address(this), testERC20); + rewardDistributor = RewardDistributor(address(registry.getRewardDistributor())); rollup = new Rollup({ - _fpcJuicePortal: new MockFeeJuicePortal(), + _feeAsset: testERC20, _rewardDistributor: rewardDistributor, _stakingAsset: testERC20, _governance: address(this), @@ -265,9 +265,15 @@ contract ValidatorSelectionTest is DecoderBase { bytes32[] memory txHashes = new bytes32[](0); - // We update the header to have 0 as the base fee - assembly { - mstore(add(add(header, 0x20), 0x0228), 0) + { + uint256 version = rollup.getVersion(); + uint256 manaBaseFee = rollup.getManaBaseFeeAt(Timestamp.wrap(block.timestamp), true); + bytes32 inHash = inbox.getRoot(full.block.decodedHeader.globalVariables.blockNumber); + assembly { + mstore(add(add(header, 0x20), 0x0064), inHash) + mstore(add(add(header, 0x20), 0x0154), version) + mstore(add(add(header, 0x20), 0x0228), manaBaseFee) + } } ProposeArgs memory args = ProposeArgs({ @@ -374,10 +380,11 @@ contract ValidatorSelectionTest is DecoderBase { } function _populateInbox(address _sender, bytes32 _recipient, bytes32[] memory _contents) internal { + uint256 version = rollup.getVersion(); for (uint256 i = 0; i < _contents.length; i++) { vm.prank(_sender); inbox.sendL2Message( - DataStructures.L2Actor({actor: _recipient, version: 1}), _contents[i], bytes32(0) + DataStructures.L2Actor({actor: _recipient, version: version}), _contents[i], bytes32(0) ); } } diff --git a/spartan/aztec-network/templates/pxe.yaml b/spartan/aztec-network/templates/pxe.yaml index cd841bb68ef0..451add017430 100644 --- a/spartan/aztec-network/templates/pxe.yaml +++ b/spartan/aztec-network/templates/pxe.yaml @@ -123,7 +123,7 @@ spec: - | curl -s -X POST -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","method":"pxe_getNodeInfo","params":[],"id":67}' \ - 127.0.0.1:{{ .Values.pxe.service.nodePort }} | grep -q '"rollupVersion":1' + 127.0.0.1:{{ .Values.pxe.service.nodePort }} | grep -q '"rollupVersion":[1-9][0-9]*' initialDelaySeconds: {{ .Values.pxe.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.pxe.readinessProbe.periodSeconds }} timeoutSeconds: {{ .Values.pxe.readinessProbe.timeoutSeconds }} diff --git a/spartan/bootstrap.sh b/spartan/bootstrap.sh index cfc98b12ed23..e560135f98ee 100755 --- a/spartan/bootstrap.sh +++ b/spartan/bootstrap.sh @@ -62,7 +62,7 @@ function test_cmds { # echo "$hash timeout -v 30m ./spartan/bootstrap.sh test-kind-4epochs" # echo "$hash timeout -v 30m ./spartan/bootstrap.sh test-kind-upgrade-rollup-version" # echo "$hash timeout -v 30m ./spartan/bootstrap.sh test-prod-deployment" - echo "$hash ./spartan/bootstrap.sh test-cli-upgrade-with-lock" + echo "$hash ./spartan/bootstrap.sh test-cli-upgrade" fi if [ "$CI_NIGHTLY" -eq 1 ]; then @@ -154,7 +154,7 @@ case "$cmd" in "test-prod-deployment") FRESH_INSTALL=false INSTALL_METRICS=false ./scripts/test_prod_deployment.sh ;; - "test-cli-upgrade-with-lock") + "test-cli-upgrade") OVERRIDES="telemetry.enabled=false,network.setupL2Contracts=false" \ FRESH_INSTALL=${FRESH_INSTALL:-true} INSTALL_METRICS=false \ ./scripts/test_kind.sh src/spartan/upgrade_via_cli.test.ts 1-validators.yaml upgrade-via-cli${NAME_POSTFIX:-} diff --git a/spartan/scripts/upgrade_rollup_with_lock.sh b/spartan/scripts/upgrade_rollup_with_cli.sh similarity index 83% rename from spartan/scripts/upgrade_rollup_with_lock.sh rename to spartan/scripts/upgrade_rollup_with_cli.sh index 5e06b03b942b..5255252b6a90 100755 --- a/spartan/scripts/upgrade_rollup_with_lock.sh +++ b/spartan/scripts/upgrade_rollup_with_cli.sh @@ -15,7 +15,7 @@ set -exu # L1_CHAIN_ID=1337 \ # ETHEREUM_HOST=http://localhost:8545 \ # MNEMONIC="test test test test test test test test test test test junk" \ -# ./upgrade_rollup_with_lock.sh \ +# ./upgrade_rollup_with_cli.sh \ # --aztec-docker-image aztecprotocol/aztec:c5e2b43044862882a68de47cac07b7116e74e51e \ # --registry 0x29f815e32efdef19883cf2b92a766b7aebadd326 \ # --address 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 \ @@ -38,7 +38,7 @@ set -exu # export AZTEC_BIN=/home/mitch/aztec-clones/alpha/yarn-project/aztec/dest/bin/index.js # L1_CHAIN_ID=1337 \ -# ./spartan/scripts/upgrade_rollup_with_lock.sh \ +# ./spartan/scripts/upgrade_rollup_with_cli.sh \ # --aztec-bin $AZTEC_BIN \ # --registry 0x29f815e32efdef19883cf2b92a766b7aebadd326 \ # --address 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 \ @@ -135,19 +135,4 @@ else EXE="node --no-warnings $AZTEC_BIN" fi - -# if DEPOSIT_AMOUNT is set, we deposit governance tokens -if [ -n "$DEPOSIT_AMOUNT" ]; then - echo "Depositing $DEPOSIT_AMOUNT governance tokens to $MY_ADDR" - $EXE deposit-governance-tokens -r $REGISTRY --recipient $MY_ADDR -a $DEPOSIT_AMOUNT $MINT -fi - -OUTPUT=$($EXE deploy-new-rollup -r $REGISTRY --salt $SALT --json $TEST_ACCOUNTS $SPONSORED_FPC) - -PAYLOAD=$(echo $OUTPUT | jq -r '.payloadAddress') - -PROPOSAL_ID=$($EXE propose-with-lock -r $REGISTRY --payload-address $PAYLOAD --json | jq -r '.proposalId') - -$EXE vote-on-governance-proposal --proposal-id $PROPOSAL_ID --in-favor true --wait true -r $REGISTRY - -$EXE execute-governance-proposal --proposal-id $PROPOSAL_ID --wait true -r $REGISTRY +$EXE deploy-new-rollup -r $REGISTRY --salt $SALT --json $TEST_ACCOUNTS $SPONSORED_FPC diff --git a/yarn-project/aztec.js/src/ethereum/portal_manager.ts b/yarn-project/aztec.js/src/ethereum/portal_manager.ts index c4cdcb0465cc..ca9b9f083869 100644 --- a/yarn-project/aztec.js/src/ethereum/portal_manager.ts +++ b/yarn-project/aztec.js/src/ethereum/portal_manager.ts @@ -437,12 +437,14 @@ export class L1TokenPortalManager extends L1ToL2TokenPortalManager { * @param l2Bridge - Address of the L2 bridge. * @param callerOnL1 - Caller address on L1. */ - public getL2ToL1MessageLeaf( + public async getL2ToL1MessageLeaf( amount: bigint, recipient: EthAddress, l2Bridge: AztecAddress, callerOnL1: EthAddress = EthAddress.ZERO, - ): Fr { + ): Promise { + const version = await this.outbox.read.VERSION(); + const content = sha256ToField([ Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), recipient.toBuffer32(), @@ -451,7 +453,7 @@ export class L1TokenPortalManager extends L1ToL2TokenPortalManager { ]); const leaf = sha256ToField([ l2Bridge.toBuffer(), - new Fr(1).toBuffer(), // aztec version + new Fr(version).toBuffer(), // aztec version EthAddress.fromString(this.portal.address).toBuffer32() ?? Buffer.alloc(32, 0), new Fr(this.publicClient.chain.id).toBuffer(), // chain id content.toBuffer(), diff --git a/yarn-project/cli/src/cmds/l1/deploy_new_rollup.ts b/yarn-project/cli/src/cmds/l1/deploy_new_rollup.ts index d47d42515a07..208f8bf1246d 100644 --- a/yarn-project/cli/src/cmds/l1/deploy_new_rollup.ts +++ b/yarn-project/cli/src/cmds/l1/deploy_new_rollup.ts @@ -29,7 +29,7 @@ export async function deployNewRollup( const initialFundedAccounts = initialAccounts.map(a => a.address).concat(sponsoredFPCAddress); const { genesisBlockHash, genesisArchiveRoot } = await getGenesisValues(initialFundedAccounts); - const { payloadAddress, rollup, slashFactoryAddress } = await deployNewRollupContracts( + const { rollup, slashFactoryAddress } = await deployNewRollupContracts( registryAddress, rpcUrls, chainId, @@ -48,7 +48,6 @@ export async function deployNewRollup( log( JSON.stringify( { - payloadAddress: payloadAddress.toString(), rollupAddress: rollup.address, initialFundedAccounts: initialFundedAccounts.map(a => a.toString()), initialValidators: initialValidators.map(a => a.toString()), @@ -61,7 +60,6 @@ export async function deployNewRollup( ), ); } else { - log(`Payload Address: ${payloadAddress.toString()}`); log(`Rollup Address: ${rollup.address}`); log(`Initial funded accounts: ${initialFundedAccounts.map(a => a.toString()).join(', ')}`); log(`Initial validators: ${initialValidators.map(a => a.toString()).join(', ')}`); diff --git a/yarn-project/cli/src/cmds/l1/index.ts b/yarn-project/cli/src/cmds/l1/index.ts index 3e6e3315cfdd..629f97ef3909 100644 --- a/yarn-project/cli/src/cmds/l1/index.ts +++ b/yarn-project/cli/src/cmds/l1/index.ts @@ -66,7 +66,7 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger program .command('deploy-new-rollup') - .description('Deploys a new rollup contract and a payload to upgrade the registry with it.') + .description('Deploys a new rollup contract and adds it to the registry (if you are the owner).') .requiredOption('-r, --registry-address ', 'The address of the registry contract', parseEthereumAddress) .addOption(l1RpcUrlsOption) .option('-pk, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) diff --git a/yarn-project/cli/src/cmds/pxe/get_node_info.ts b/yarn-project/cli/src/cmds/pxe/get_node_info.ts index b7d09f200d32..317629e7f618 100644 --- a/yarn-project/cli/src/cmds/pxe/get_node_info.ts +++ b/yarn-project/cli/src/cmds/pxe/get_node_info.ts @@ -36,6 +36,7 @@ export async function getNodeInfo( governance: info.l1ContractAddresses.governanceAddress.toString(), slashFactory: info.l1ContractAddresses.slashFactoryAddress?.toString(), feeAssetHandler: info.l1ContractAddresses.feeAssetHandlerAddress?.toString(), + stakingAssetHandler: info.l1ContractAddresses.stakingAssetHandlerAddress?.toString(), }, protocolContractAddresses: { classRegisterer: info.protocolContractAddresses.classRegisterer.toString(), @@ -63,6 +64,7 @@ export async function getNodeInfo( log(` Governance Address: ${info.l1ContractAddresses.governanceAddress.toString()}`); log(` SlashFactory Address: ${info.l1ContractAddresses.slashFactoryAddress?.toString()}`); log(` FeeAssetHandler Address: ${info.l1ContractAddresses.feeAssetHandlerAddress?.toString()}`); + log(` StakingAssetHandler Address: ${info.l1ContractAddresses.stakingAssetHandlerAddress?.toString()}`); log(`L2 Contract Addresses:`); log(` Class Registerer: ${info.protocolContractAddresses.classRegisterer.toString()}`); log(` Fee Juice: ${info.protocolContractAddresses.feeJuice.toString()}`); diff --git a/yarn-project/cli/src/utils/aztec.ts b/yarn-project/cli/src/utils/aztec.ts index 14f889f12f71..a4fa5c46e9e8 100644 --- a/yarn-project/cli/src/utils/aztec.ts +++ b/yarn-project/cli/src/utils/aztec.ts @@ -96,7 +96,7 @@ export async function deployNewRollupContracts( genesisBlockHash: Fr, config: L1ContractsConfig, logger: Logger, -): Promise<{ payloadAddress: EthAddress; rollup: RollupContract; slashFactoryAddress: EthAddress }> { +): Promise<{ rollup: RollupContract; slashFactoryAddress: EthAddress }> { const { createEthereumChain, deployRollupForUpgrade, createL1Clients } = await import('@aztec/ethereum'); const { mnemonicToAccount, privateKeyToAccount } = await import('viem/accounts'); const { getVKTreeRoot } = await import('@aztec/noir-protocol-circuits-types/vk-tree'); @@ -107,7 +107,7 @@ export async function deployNewRollupContracts( const chain = createEthereumChain(rpcUrls, chainId); const clients = createL1Clients(rpcUrls, account, chain.chainInfo, mnemonicIndex); - const { payloadAddress, rollup, slashFactoryAddress } = await deployRollupForUpgrade( + const { rollup, slashFactoryAddress } = await deployRollupForUpgrade( clients, { salt, @@ -124,7 +124,7 @@ export async function deployNewRollupContracts( config, ); - return { payloadAddress, rollup, slashFactoryAddress }; + return { rollup, slashFactoryAddress }; } /** diff --git a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts index 9f15b2282157..419e5db3c5af 100644 --- a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts @@ -232,7 +232,7 @@ describe('L1Publisher integration', () => { coinbase = config.coinbase || EthAddress.random(); feeRecipient = config.feeRecipient || (await AztecAddress.random()); - version = config.rollupVersion ?? 1; + version = Number(await rollup.getVersion()); const fork = await worldStateSynchronizer.fork(); diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l2_to_l1.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l2_to_l1.test.ts index bbe6be8e9931..6def7510c342 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l2_to_l1.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l2_to_l1.test.ts @@ -1,4 +1,5 @@ import { Fr } from '@aztec/aztec.js'; +import { RollupContract } from '@aztec/ethereum'; import { sha256ToField } from '@aztec/foundation/crypto'; import { OutboxAbi } from '@aztec/l1-artifacts'; import { TestContract } from '@aztec/noir-contracts.js/Test'; @@ -10,6 +11,8 @@ import { CrossChainMessagingTest } from './cross_chain_messaging_test.js'; describe('e2e_cross_chain_messaging l2_to_l1', () => { const t = new CrossChainMessagingTest('l2_to_l1'); + let version: number = 1; + let { crossChainTestHarness, aztecNode, user1Wallet, outbox } = t; beforeAll(async () => { @@ -25,6 +28,13 @@ describe('e2e_cross_chain_messaging l2_to_l1', () => { abi: OutboxAbi, client: crossChainTestHarness.walletClient, }); + + version = Number( + await new RollupContract( + crossChainTestHarness.publicClient, + crossChainTestHarness.l1ContractAddresses.rollupAddress.toString(), + ).getVersion(), + ); }, 300_000); afterAll(async () => { @@ -57,7 +67,7 @@ describe('e2e_cross_chain_messaging l2_to_l1', () => { } const l2ToL1Message = { - sender: { actor: testContract.address.toString() as Hex, version: 1n }, + sender: { actor: testContract.address.toString() as Hex, version: BigInt(version) }, recipient: { actor: recipient.toString() as Hex, chainId: BigInt(crossChainTestHarness.publicClient.chain.id), @@ -67,7 +77,7 @@ describe('e2e_cross_chain_messaging l2_to_l1', () => { const leaf = sha256ToField([ testContract.address, - new Fr(1), // aztec version + new Fr(version), // aztec version recipient.toBuffer32(), new Fr(crossChainTestHarness.publicClient.chain.id), // chain id content, diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_failure_cases.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_failure_cases.test.ts index f91f0ab555e0..9c8391a470f6 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_failure_cases.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_failure_cases.test.ts @@ -1,4 +1,5 @@ import { EthAddress, Fr, L1Actor, L1ToL2Message, L2Actor } from '@aztec/aztec.js'; +import { RollupContract } from '@aztec/ethereum'; import { sha256ToField } from '@aztec/foundation/crypto'; import { toFunctionSelector } from 'viem'; @@ -8,6 +9,7 @@ import { CrossChainMessagingTest } from './cross_chain_messaging_test.js'; describe('e2e_cross_chain_messaging token_bridge_failure_cases', () => { const t = new CrossChainMessagingTest('token_bridge_failure_cases'); + let version: number = 1; let { crossChainTestHarness, ethAccount, l2Bridge, user1Wallet, user2Wallet, ownerAddress } = t; @@ -19,6 +21,12 @@ describe('e2e_cross_chain_messaging token_bridge_failure_cases', () => { ethAccount = crossChainTestHarness.ethAccount; l2Bridge = crossChainTestHarness.l2Bridge; ownerAddress = crossChainTestHarness.ownerAddress; + + const rollup = new RollupContract( + crossChainTestHarness.publicClient, + crossChainTestHarness.l1ContractAddresses.rollupAddress.toString(), + ); + version = Number(await rollup.getVersion()); }, 300_000); afterAll(async () => { @@ -58,7 +66,7 @@ describe('e2e_cross_chain_messaging token_bridge_failure_cases', () => { const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), - new L2Actor(l2Bridge.address, 1), + new L2Actor(l2Bridge.address, version), wrongMessageContent, claim.claimSecretHash, new Fr(claim.messageLeafIndex), diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_private.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_private.test.ts index 5166fe7ab470..ed0f821c5235 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_private.test.ts @@ -78,7 +78,7 @@ describe('e2e_cross_chain_messaging token_bridge_private', () => { // docs:end:authwit_to_another_sc // 5. Withdraw owner's funds from L2 to L1 - const l2ToL1Message = crossChainTestHarness.getL2ToL1MessageLeaf(withdrawAmount); + const l2ToL1Message = await crossChainTestHarness.getL2ToL1MessageLeaf(withdrawAmount); const l2TxReceipt = await crossChainTestHarness.withdrawPrivateFromAztecToL1(withdrawAmount, nonce, burnAuthwit); await crossChainTestHarness.expectPrivateBalanceOnL2(ownerAddress, bridgeAmount - withdrawAmount); diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_public.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_public.test.ts index 925b6e71eaf3..865fdd4d9f4b 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_public.test.ts @@ -84,7 +84,7 @@ describe('e2e_cross_chain_messaging token_bridge_public', () => { // 5. Withdraw owner's funds from L2 to L1 logger.verbose('5. Withdraw owner funds from L2 to L1'); - const l2ToL1Message = crossChainTestHarness.getL2ToL1MessageLeaf(withdrawAmount); + const l2ToL1Message = await crossChainTestHarness.getL2ToL1MessageLeaf(withdrawAmount); const l2TxReceipt = await crossChainTestHarness.withdrawPublicFromAztecToL1(withdrawAmount, nonce); await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, afterBalance - withdrawAmount); diff --git a/yarn-project/end-to-end/src/e2e_outbox.test.ts b/yarn-project/end-to-end/src/e2e_outbox.test.ts index 5d3e1da9615f..9b1fa55d6afb 100644 --- a/yarn-project/end-to-end/src/e2e_outbox.test.ts +++ b/yarn-project/end-to-end/src/e2e_outbox.test.ts @@ -7,7 +7,7 @@ import { type SiblingPath, } from '@aztec/aztec.js'; import { CheatCodes } from '@aztec/aztec.js/testing'; -import type { DeployL1ContractsReturnType } from '@aztec/ethereum'; +import { type DeployL1ContractsReturnType, RollupContract } from '@aztec/ethereum'; import { sha256ToField } from '@aztec/foundation/crypto'; import { truncateAndPad } from '@aztec/foundation/serialize'; import { OutboxAbi } from '@aztec/l1-artifacts'; @@ -30,6 +30,7 @@ describe('E2E Outbox Tests', () => { let deployL1ContractsValues: DeployL1ContractsReturnType; let outbox: any; let cheatCodes: CheatCodes; + let version: number = 1; beforeEach(async () => { ({ teardown, aztecNode, wallets, deployL1ContractsValues, cheatCodes, aztecNodeAdmin } = await setup(1)); @@ -39,6 +40,12 @@ describe('E2E Outbox Tests', () => { client: deployL1ContractsValues.walletClient, }); + const rollup = new RollupContract( + deployL1ContractsValues.publicClient, + deployL1ContractsValues.l1ContractAddresses.rollupAddress.toString(), + ); + version = Number(await rollup.getVersion()); + const receipt = await TestContract.deploy(wallets[0]).send({ contractAddressSalt: Fr.ZERO }).wait(); contract = receipt.contract; }); @@ -108,7 +115,7 @@ describe('E2E Outbox Tests', () => { // Consume msg 2 // Taken from l2_to_l1.test const msg2 = { - sender: { actor: contract.address.toString() as `0x${string}`, version: 1n }, + sender: { actor: contract.address.toString() as `0x${string}`, version: BigInt(version) }, recipient: { actor: recipient2.toString() as `0x${string}`, chainId: BigInt(deployL1ContractsValues.publicClient.chain.id), @@ -227,7 +234,7 @@ describe('E2E Outbox Tests', () => { // Consume msg 2 // Taken from l2_to_l1.test const msg2 = { - sender: { actor: contract.address.toString() as `0x${string}`, version: 1n }, + sender: { actor: contract.address.toString() as `0x${string}`, version: BigInt(version) }, recipient: { actor: recipient2.toString() as `0x${string}`, chainId: BigInt(deployL1ContractsValues.publicClient.chain.id), @@ -344,7 +351,7 @@ describe('E2E Outbox Tests', () => { // Consume msg 2 // Taken from l2_to_l1.test const msg2 = { - sender: { actor: contract.address.toString() as `0x${string}`, version: 1n }, + sender: { actor: contract.address.toString() as `0x${string}`, version: BigInt(version) }, recipient: { actor: recipient2.toString() as `0x${string}`, chainId: BigInt(deployL1ContractsValues.publicClient.chain.id), @@ -426,7 +433,7 @@ describe('E2E Outbox Tests', () => { function makeL2ToL1Message(recipient: EthAddress, content: Fr = Fr.ZERO): Fr { const leaf = sha256ToField([ contract.address, - new Fr(1), // aztec version + new Fr(version), recipient.toBuffer32(), new Fr(deployL1ContractsValues.publicClient.chain.id), // chain id content, diff --git a/yarn-project/end-to-end/src/e2e_prover/full.test.ts b/yarn-project/end-to-end/src/e2e_prover/full.test.ts index 7b9538c1cd4a..5513acf3b731 100644 --- a/yarn-project/end-to-end/src/e2e_prover/full.test.ts +++ b/yarn-project/end-to-end/src/e2e_prover/full.test.ts @@ -85,7 +85,7 @@ describe('full_prover', () => { expect(balance).toBeGreaterThan(0n); - const canonicalAddress = await feeJuicePortal.read.canonicalRollup(); + const canonicalAddress = await feeJuicePortal.read.ROLLUP(); logger.info(`Canonical address: ${canonicalAddress}`); expect(canonicalAddress.toLowerCase()).toBe( t.l1Contracts.l1ContractAddresses.rollupAddress.toString().toLowerCase(), diff --git a/yarn-project/end-to-end/src/e2e_token_bridge_tutorial_test.test.ts b/yarn-project/end-to-end/src/e2e_token_bridge_tutorial_test.test.ts index f169fce9e1f9..7f54eadd46d3 100644 --- a/yarn-project/end-to-end/src/e2e_token_bridge_tutorial_test.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_bridge_tutorial_test.test.ts @@ -196,7 +196,7 @@ describe('e2e_cross_chain_messaging token_bridge_tutorial_test', () => { // docs:end:setup-withdrawal // docs:start:l2-withdraw - const l2ToL1Message = l1PortalManager.getL2ToL1MessageLeaf( + const l2ToL1Message = await l1PortalManager.getL2ToL1MessageLeaf( withdrawAmount, EthAddress.fromString(ownerEthAddress), l2BridgeContract.address, diff --git a/yarn-project/end-to-end/src/fixtures/l1_to_l2_messaging.ts b/yarn-project/end-to-end/src/fixtures/l1_to_l2_messaging.ts index bf99cd3710b0..025c31a8546a 100644 --- a/yarn-project/end-to-end/src/fixtures/l1_to_l2_messaging.ts +++ b/yarn-project/end-to-end/src/fixtures/l1_to_l2_messaging.ts @@ -1,4 +1,9 @@ -import type { L1ContractAddresses, ViemPublicClient, ViemWalletClient } from '@aztec/ethereum'; +import { + type L1ContractAddresses, + RollupContract, + type ViemPublicClient, + type ViemWalletClient, +} from '@aztec/ethereum'; import { Fr } from '@aztec/foundation/fields'; import { InboxAbi } from '@aztec/l1-artifacts'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; @@ -11,7 +16,7 @@ export async function sendL1ToL2Message( ctx: { walletClient: ViemWalletClient; publicClient: ViemPublicClient; - l1ContractAddresses: Pick; + l1ContractAddresses: Pick; }, ) { const inbox = getContract({ @@ -21,7 +26,11 @@ export async function sendL1ToL2Message( }); const { recipient, content, secretHash } = message; - const version = 1; + + const version = await new RollupContract( + ctx.publicClient, + ctx.l1ContractAddresses.rollupAddress.toString(), + ).getVersion(); // We inject the message to Inbox const txHash = await inbox.write.sendL2Message([ diff --git a/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts b/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts index 62bb7d8d69d8..de349855ab4f 100644 --- a/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts +++ b/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts @@ -325,8 +325,8 @@ export class CrossChainTestHarness { expect(balance).toBe(expectedBalance); } - getL2ToL1MessageLeaf(withdrawAmount: bigint, callerOnL1: EthAddress = EthAddress.ZERO): Fr { - return this.l1TokenPortalManager.getL2ToL1MessageLeaf( + async getL2ToL1MessageLeaf(withdrawAmount: bigint, callerOnL1: EthAddress = EthAddress.ZERO): Promise { + return await this.l1TokenPortalManager.getL2ToL1MessageLeaf( withdrawAmount, this.ethAccount, this.l2Bridge.address, diff --git a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts index 1e3493c9f4e9..ca38032bf019 100644 --- a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts +++ b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts @@ -101,7 +101,7 @@ export const uniswapL1L2TestSuite = ( const minimumOutputAmount = 0n; let cheatCodes: CheatCodes; - + let version: number; beforeAll(async () => { ({ aztecNode, @@ -123,7 +123,7 @@ export const uniswapL1L2TestSuite = ( deployL1ContractsValues.publicClient, deployL1ContractsValues.l1ContractAddresses.rollupAddress, ); - + version = Number(await rollup.getVersion()); ownerAddress = ownerWallet.getAddress(); // sponsorAddress = sponsorWallet.getAddress(); ownerEthAddress = EthAddress.fromString((await walletClient.getAddresses())[0]); @@ -261,7 +261,7 @@ export const uniswapL1L2TestSuite = ( const swapPrivateLeaf = sha256ToField([ uniswapL2Contract.address, - new Fr(1), // aztec version + new Fr(version), // aztec version EthAddress.fromString(uniswapPortal.address).toBuffer32(), new Fr(publicClient.chain.id), // chain id swapPrivateContent, @@ -276,7 +276,7 @@ export const uniswapL1L2TestSuite = ( const withdrawLeaf = sha256ToField([ wethCrossChainHarness.l2Bridge.address, - new Fr(1), // aztec version + new Fr(version), // aztec version wethCrossChainHarness.tokenPortalAddress.toBuffer32(), new Fr(publicClient.chain.id), // chain id withdrawContent, @@ -849,7 +849,7 @@ export const uniswapL1L2TestSuite = ( const swapPrivateLeaf = sha256ToField([ uniswapL2Contract.address, - new Fr(1), // aztec version + new Fr(version), // aztec version EthAddress.fromString(uniswapPortal.address).toBuffer32(), new Fr(publicClient.chain.id), // chain id swapPrivateContent, @@ -864,7 +864,7 @@ export const uniswapL1L2TestSuite = ( const withdrawLeaf = sha256ToField([ wethCrossChainHarness.l2Bridge.address, - new Fr(1), // aztec version + new Fr(version), // aztec version wethCrossChainHarness.tokenPortalAddress.toBuffer32(), new Fr(publicClient.chain.id), // chain id withdrawContent, @@ -979,7 +979,7 @@ export const uniswapL1L2TestSuite = ( const swapPublicLeaf = sha256ToField([ uniswapL2Contract.address, - new Fr(1), // aztec version + new Fr(version), // aztec version EthAddress.fromString(uniswapPortal.address).toBuffer32(), new Fr(publicClient.chain.id), // chain id swapPublicContent, @@ -994,7 +994,7 @@ export const uniswapL1L2TestSuite = ( const withdrawLeaf = sha256ToField([ wethCrossChainHarness.l2Bridge.address, - new Fr(1), // aztec version + new Fr(version), // aztec version wethCrossChainHarness.tokenPortalAddress.toBuffer32(), new Fr(publicClient.chain.id), // chain id withdrawContent, diff --git a/yarn-project/end-to-end/src/spartan/smoke.test.ts b/yarn-project/end-to-end/src/spartan/smoke.test.ts index 0cece0a56e26..815610eea9bd 100644 --- a/yarn-project/end-to-end/src/spartan/smoke.test.ts +++ b/yarn-project/end-to-end/src/spartan/smoke.test.ts @@ -36,6 +36,8 @@ describe('smoke test', () => { it('should be able to get node enr', async () => { const info = await pxe.getNodeInfo(); + + debugLogger.info(`info: ${JSON.stringify(info)}`); expect(info).toBeDefined(); // expect enr to be a string starting with 'enr:-' expect(info.enr).toMatch(/^enr:-/); diff --git a/yarn-project/end-to-end/src/spartan/upgrade_rollup_version.test.ts b/yarn-project/end-to-end/src/spartan/upgrade_rollup_version.test.ts index 7de96e8817bf..356a7e4dd1f8 100644 --- a/yarn-project/end-to-end/src/spartan/upgrade_rollup_version.test.ts +++ b/yarn-project/end-to-end/src/spartan/upgrade_rollup_version.test.ts @@ -1,10 +1,7 @@ import { getInitialTestAccounts } from '@aztec/accounts/testing'; -import { type NodeInfo, type PXE, createCompatibleClient, retryUntil, sleep } from '@aztec/aztec.js'; +import { type NodeInfo, type PXE, createCompatibleClient, retryUntil } from '@aztec/aztec.js'; import { - GovernanceContract, - GovernanceProposerContract, type L1ContractAddresses, - L1TxUtils, RegistryContract, RollupContract, createEthereumChain, @@ -13,17 +10,14 @@ import { deployRollupForUpgrade, } from '@aztec/ethereum'; import { createLogger } from '@aztec/foundation/log'; -import { TestERC20Abi as FeeJuiceAbi } from '@aztec/l1-artifacts/TestERC20Abi'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree'; import { ProtocolContractAddress, protocolContractTreeRoot } from '@aztec/protocol-contracts'; import { getGenesisValues } from '@aztec/world-state/testing'; import type { ChildProcess } from 'child_process'; import omit from 'lodash.omit'; -import { getContract } from 'viem'; -import { stringify } from 'viem/utils'; -import { isK8sConfig, rollAztecPods, setupEnvironment, startPortForward, updateSequencersConfig } from './utils.js'; +import { isK8sConfig, rollAztecPods, setupEnvironment, startPortForward } from './utils.js'; const config = setupEnvironment(process.env); if (!isK8sConfig(config)) { @@ -62,30 +56,21 @@ describe('spartan_upgrade_rollup_version', () => { pxe = await createCompatibleClient(PXE_URL, debugLogger); nodeInfo = await pxe.getNodeInfo(); - originalL1ContractAddresses = omit(nodeInfo.l1ContractAddresses, 'slashFactoryAddress'); + originalL1ContractAddresses = omit(nodeInfo.l1ContractAddresses, [ + 'slashFactoryAddress', + 'stakingAssetHandlerAddress', + 'feeAssetHandlerAddress', + ]); }); // We need a separate account to deploy the new governance proposer // because the underlying validators are currently producing blob transactions // and you can't submit blob and non-blob transactions from the same account + // @note Look at older commits to find a version that actually go through governance here it( 'should upgrade the rollup version', async () => { - /** Helpers */ - const govInfo = async () => { - const bn = await l1PublicClient.getBlockNumber(); - const slot = await rollup.getSlotNumber(); - const round = await governanceProposer.computeRound(slot); - const info = await governanceProposer.getRoundInfo(originalL1ContractAddresses.rollupAddress.toString(), round); - const leaderVotes = await governanceProposer.getProposalVotes( - originalL1ContractAddresses.rollupAddress.toString(), - round, - info.leader, - ); - return { bn, slot, round, info, leaderVotes }; - }; - /** Setup */ const chain = createEthereumChain(ETHEREUM_HOSTS, nodeInfo.l1ChainId); @@ -99,7 +84,8 @@ describe('spartan_upgrade_rollup_version', () => { const { genesisBlockHash, genesisArchiveRoot } = await getGenesisValues(initialTestAccounts.map(a => a.address)); - const { rollup: newRollup, payloadAddress } = await deployRollupForUpgrade( + const rollup = new RollupContract(l1PublicClient, originalL1ContractAddresses.rollupAddress.toString()); + const { rollup: newRollup } = await deployRollupForUpgrade( { walletClient: l1WalletClient, publicClient: l1PublicClient, @@ -129,112 +115,6 @@ describe('spartan_upgrade_rollup_version', () => { defaultL1TxUtilsConfig, ); - await updateSequencersConfig(config, { - governanceProposerPayload: payloadAddress, - }); - - const rollup = new RollupContract(l1PublicClient, originalL1ContractAddresses.rollupAddress.toString()); - const governanceProposer = new GovernanceProposerContract( - l1PublicClient, - originalL1ContractAddresses.governanceProposerAddress.toString(), - ); - - let info = await govInfo(); - expect(info.bn).toBeDefined(); - expect(info.slot).toBeDefined(); - debugLogger.info(`info: ${stringify(info)}`); - - const quorumSize = await governanceProposer.getQuorumSize(); - debugLogger.info(`quorumSize: ${quorumSize}`); - expect(quorumSize).toBeGreaterThan(0); - - /** GovernanceProposer Voting */ - - // Wait until we have enough votes to execute the proposal. - while (true) { - info = await govInfo(); - debugLogger.info(`Leader votes: ${info.leaderVotes}`); - if (info.leaderVotes >= quorumSize) { - debugLogger.info(`Leader votes have reached quorum size`); - break; - } - await sleep(12000); - } - - const executableRound = info.round; - debugLogger.info(`Waiting for round ${executableRound + 1n}`); - - while (info.round === executableRound) { - await sleep(12500); - info = await govInfo(); - debugLogger.info(`slot: ${info.slot}`); - } - - expect(info.round).toBeGreaterThan(executableRound); - - debugLogger.info(`Executing proposal ${info.round}`); - - const l1TxUtils = new L1TxUtils(l1PublicClient, l1WalletClient, debugLogger); - const { receipt, proposalId } = await governanceProposer.executeProposal(executableRound, l1TxUtils); - expect(receipt).toBeDefined(); - expect(receipt.status).toEqual('success'); - debugLogger.info(`Executed proposal ${info.round}`, receipt); - - const addresses = await RegistryContract.collectAddresses( - l1PublicClient, - originalL1ContractAddresses.registryAddress, - 'canonical', - ); - - // Set up the primary voter - const token = getContract({ - address: addresses.feeJuiceAddress.toString(), - abi: FeeJuiceAbi, - client: l1PublicClient, - }); - - const governance = new GovernanceContract(addresses.governanceAddress.toString(), l1PublicClient, l1WalletClient); - const { minimumVotes: voteAmount } = await governance.getConfiguration(); - - const mintTx = await token.write.mint([l1WalletClient.account.address, voteAmount], { - account: l1WalletClient.account, - }); - await l1PublicClient.waitForTransactionReceipt({ hash: mintTx }); - - const approveTx = await token.write.approve([addresses.governanceAddress.toString(), voteAmount], { - account: l1WalletClient.account, - }); - await l1PublicClient.waitForTransactionReceipt({ hash: approveTx }); - - await governance.deposit(l1WalletClient.account.address, voteAmount); - - await governance.awaitProposalActive({ - proposalId, - logger: debugLogger, - }); - - // Vote for the proposal - await governance.vote({ - proposalId, - voteAmount, - inFavor: true, - retries: 10, - logger: debugLogger, - }); - - // Wait for the proposal to be in the executable phase - await governance.awaitProposalExecutable({ - proposalId, - logger: debugLogger, - }); - - // Execute the proposal - await governance.executeProposal({ - proposalId, - retries: 10, - logger: debugLogger, - }); - const newAddresses = await newRollup.getRollupAddresses(); const newCanonicalAddresses = await RegistryContract.collectAddresses( @@ -250,14 +130,27 @@ describe('spartan_upgrade_rollup_version', () => { ...newAddresses, }); - await expect( - RegistryContract.collectAddresses(l1PublicClient, originalL1ContractAddresses.registryAddress, 2), - ).resolves.toEqual(newCanonicalAddresses); + const oldVersion = await new RollupContract( + l1PublicClient, + originalL1ContractAddresses.rollupAddress.toString(), + ).getVersion(); + const newVersion = await new RollupContract( + l1PublicClient, + newCanonicalAddresses.rollupAddress.toString(), + ).getVersion(); + + debugLogger.info(`oldVersion: ${oldVersion}, address: ${originalL1ContractAddresses.rollupAddress}`); + debugLogger.info(`newVersion: ${newVersion}, address: ${newCanonicalAddresses.rollupAddress}`); + expect(oldVersion).not.toEqual(newVersion); await expect( - RegistryContract.collectAddresses(l1PublicClient, originalL1ContractAddresses.registryAddress, 1), + RegistryContract.collectAddresses(l1PublicClient, originalL1ContractAddresses.registryAddress, oldVersion), ).resolves.toEqual(originalL1ContractAddresses); + await expect( + RegistryContract.collectAddresses(l1PublicClient, originalL1ContractAddresses.registryAddress, newVersion), + ).resolves.toEqual(newCanonicalAddresses); + const oldRollupTips = await rollup.getTips(); await retryUntil( async () => { @@ -284,6 +177,13 @@ describe('spartan_upgrade_rollup_version', () => { pxe = await createCompatibleClient(PXE_URL, debugLogger); const newNodeInfo = await pxe.getNodeInfo(); + + // @todo There is an issue here, probably related to #12791, but somehow + // the address returned by the pxe node info is NEITHER the old nor the new rollup address + + debugLogger.info(`newNodeInfo: ${JSON.stringify(newNodeInfo)}`); + debugLogger.info(`originalL1ContractAddresses: ${JSON.stringify(originalL1ContractAddresses)}`); + debugLogger.info(`newCanonicalAddresses: ${JSON.stringify(newCanonicalAddresses)}`); expect(newNodeInfo.l1ContractAddresses.rollupAddress).toEqual(newCanonicalAddresses.rollupAddress); const l2Tips = await newRollup.getTips(); diff --git a/yarn-project/end-to-end/src/spartan/upgrade_via_cli.test.ts b/yarn-project/end-to-end/src/spartan/upgrade_via_cli.test.ts index 0d22cb53b2f8..064a89d63980 100644 --- a/yarn-project/end-to-end/src/spartan/upgrade_via_cli.test.ts +++ b/yarn-project/end-to-end/src/spartan/upgrade_via_cli.test.ts @@ -74,7 +74,7 @@ describe('upgrade via cli', () => { const oldNumberOfVersions = await registry.getNumberOfVersions(); const exitCode = await runProjectScript( - 'spartan/scripts/upgrade_rollup_with_lock.sh', + 'spartan/scripts/upgrade_rollup_with_cli.sh', [ '--aztec-bin', getAztecBin(), diff --git a/yarn-project/ethereum/src/contracts/registry.test.ts b/yarn-project/ethereum/src/contracts/registry.test.ts index 2c6a0754b747..a1016aa8f509 100644 --- a/yarn-project/ethereum/src/contracts/registry.test.ts +++ b/yarn-project/ethereum/src/contracts/registry.test.ts @@ -7,13 +7,13 @@ import { type PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts'; import { foundry } from 'viem/chains'; import { DefaultL1ContractsConfig } from '../config.js'; -import { createL1Clients, deployL1Contracts, deployRollupForUpgrade } from '../deploy_l1_contracts.js'; +import { L1Deployer, createL1Clients, deployL1Contracts, deployRollup } from '../deploy_l1_contracts.js'; import type { L1ContractAddresses } from '../l1_contract_addresses.js'; import { defaultL1TxUtilsConfig } from '../l1_tx_utils.js'; import { startAnvil } from '../test/start_anvil.js'; -import { createGovernanceProposal, executeGovernanceProposal } from '../test/upgrade_utils.js'; import type { L1Clients } from '../types.js'; import { RegistryContract } from './registry.js'; +import { RollupContract } from './rollup.js'; const originalVersionSalt = 42; @@ -30,6 +30,7 @@ describe('Registry', () => { let walletClient: L1Clients['walletClient']; let registry: RegistryContract; let deployedAddresses: L1ContractAddresses; + let deployedVersion: number; beforeAll(async () => { logger = createLogger('ethereum:test:registry'); @@ -55,6 +56,9 @@ describe('Registry', () => { // Since the registry cannot "see" the slash factory, we omit it from the addresses for this test deployedAddresses = omit(deployed.l1ContractAddresses, 'slashFactoryAddress', 'feeAssetHandlerAddress'); registry = new RegistryContract(publicClient, deployedAddresses.registryAddress); + + const rollup = new RollupContract(publicClient, deployedAddresses.rollupAddress); + deployedVersion = Number(await rollup.getVersion()); }); afterAll(async () => { @@ -72,13 +76,13 @@ describe('Registry', () => { expect(address).toEqual(rollupAddress); } { - const address = await registry.getRollupAddress(1); + const address = await registry.getRollupAddress(deployedVersion); expect(address).toEqual(rollupAddress); } }); it('handles non-existent versions', async () => { - await expect(registry.getRollupAddress(2)).rejects.toThrow('Rollup address is undefined'); + await expect(registry.getRollupAddress(2n)).rejects.toThrow('Rollup address is undefined'); }); it('collects addresses', async () => { @@ -87,29 +91,34 @@ describe('Registry', () => { ).resolves.toEqual(deployedAddresses); await expect( - RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 1), + RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, deployedVersion), ).resolves.toEqual(deployedAddresses); // Version 2 does not exist - await expect(RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 2)).rejects.toThrow( - 'Rollup address is undefined', - ); + await expect( + RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 2n), + ).rejects.toThrow('Rollup address is undefined'); }); it('adds a version to the registry', async () => { - const addresses = await RegistryContract.collectAddresses( + const newVersionSalt = originalVersionSalt + 1; + + const deployer = new L1Deployer( + walletClient, publicClient, - deployedAddresses.registryAddress, - 'canonical', + newVersionSalt, + undefined, + logger, + defaultL1TxUtilsConfig, ); - const newVersionSalt = originalVersionSalt + 1; - const { rollup: newRollup, payloadAddress } = await deployRollupForUpgrade( + const { rollup: newRollup } = await deployRollup( { walletClient, publicClient, }, + deployer, { ...DefaultL1ContractsConfig, salt: newVersionSalt, @@ -119,27 +128,7 @@ describe('Registry', () => { genesisArchiveRoot: Fr.random(), genesisBlockHash: Fr.random(), }, - deployedAddresses.registryAddress, - logger, - defaultL1TxUtilsConfig, - ); - - const { governance, voteAmount, proposalId } = await createGovernanceProposal( - payloadAddress.toString(), - addresses, - privateKey, - publicClient, - logger, - ); - - await executeGovernanceProposal( - proposalId, - governance, - voteAmount, - privateKey, - publicClient, - walletClient, - [rpcUrl], + deployedAddresses, logger, ); @@ -157,11 +146,11 @@ describe('Registry', () => { }); await expect( - RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 2), + RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, await newRollup.getVersion()), ).resolves.toEqual(newCanonicalAddresses); await expect( - RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 1), + RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, deployedVersion), ).resolves.toEqual(deployedAddresses); }); }); diff --git a/yarn-project/ethereum/src/contracts/registry.ts b/yarn-project/ethereum/src/contracts/registry.ts index 7c5ded5db51f..7fd30fb26caa 100644 --- a/yarn-project/ethereum/src/contracts/registry.ts +++ b/yarn-project/ethereum/src/contracts/registry.ts @@ -42,12 +42,11 @@ export class RegistryContract { version = BigInt(version); } - const snapshot = await this.registry.read.getSnapshot([version]); - const address = EthAddress.fromString(snapshot.rollup); - if (address.equals(EthAddress.ZERO)) { + try { + return EthAddress.fromString(await this.registry.read.getRollup([version])); + } catch (e) { throw new Error('Rollup address is undefined'); } - return address; } /** @@ -55,12 +54,7 @@ export class RegistryContract { * @returns The canonical address of the rollup. If the rollup is not set, throws an error. */ public async getCanonicalAddress(): Promise { - const snapshot = await this.registry.read.getCurrentSnapshot(); - const address = EthAddress.fromString(snapshot.rollup); - if (address.equals(EthAddress.ZERO)) { - throw new Error('Rollup address is undefined'); - } - return address; + return EthAddress.fromString(await this.registry.read.getCanonicalRollup()); } public async getGovernanceAddresses(): Promise< @@ -108,4 +102,19 @@ export class RegistryContract { const version = await this.registry.read.numberOfVersions(); return Number(version); } + + public async getRollupVersions(): Promise { + const count = await this.getNumberOfVersions(); + + const versions: bigint[] = []; + for (let i = 0; i < count; i++) { + versions.push(await this.registry.read.getVersion([BigInt(i)])); + } + + return versions; + } + + public async getRewardDistributor(): Promise { + return EthAddress.fromString(await this.registry.read.getRewardDistributor()); + } } diff --git a/yarn-project/ethereum/src/contracts/rollup.ts b/yarn-project/ethereum/src/contracts/rollup.ts index f5af2bec5e1b..b8c45a732d81 100644 --- a/yarn-project/ethereum/src/contracts/rollup.ts +++ b/yarn-project/ethereum/src/contracts/rollup.ts @@ -140,6 +140,11 @@ export class RollupContract { return this.rollup.read.getManaLimit(); } + @memoize + getVersion() { + return this.rollup.read.getVersion(); + } + getSlasher() { return this.rollup.read.getSlasher(); } @@ -276,6 +281,10 @@ export class RollupContract { }; } + public async getFeeJuicePortal() { + return EthAddress.fromString(await this.rollup.read.getFeeAssetPortal()); + } + public async getEpochNumberForSlotNumber(slotNumber: bigint): Promise { return await this.rollup.read.getEpochAtSlot([slotNumber]); } @@ -360,10 +369,6 @@ export class RollupContract { return this.rollup.read.getManaBaseFeeAt([timestamp, inFeeAsset]); } - getVersion() { - return this.rollup.read.getVersion(); - } - getSlotAt(timestamp: bigint) { return this.rollup.read.getSlotAt([timestamp]); } diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index 64ac544b508c..b4f0821916bc 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -31,6 +31,8 @@ import { RollupLinkReferences, SlashFactoryAbi, SlashFactoryBytecode, + StakingAssetHandlerAbi, + StakingAssetHandlerBytecode, TestERC20Abi, TestERC20Bytecode, ValidatorSelectionLibAbi, @@ -194,6 +196,10 @@ export const l1Artifacts = { contractAbi: FeeAssetHandlerAbi, contractBytecode: FeeAssetHandlerBytecode as Hex, }, + stakingAssetHandler: { + contractAbi: StakingAssetHandlerAbi, + contractBytecode: StakingAssetHandlerBytecode as Hex, + }, }; export interface DeployL1ContractsArgs extends L1ContractsConfig { @@ -263,8 +269,165 @@ export function createL1Clients( return { walletClient, publicClient } as L1Clients; } +export const deploySharedContracts = async ( + clients: L1Clients, + deployer: L1Deployer, + args: DeployL1ContractsArgs, + logger: Logger, +) => { + const txHashes: Hex[] = []; + + const feeAssetAddress = await deployer.deploy(l1Artifacts.feeAsset, [ + 'FeeJuice', + 'FEE', + clients.walletClient.account.address.toString(), + ]); + logger.verbose(`Deployed Fee Asset at ${feeAssetAddress}`); + + const stakingAssetAddress = await deployer.deploy(l1Artifacts.stakingAsset, [ + 'Staking', + 'STK', + clients.walletClient.account.address.toString(), + ]); + logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`); + + const registryAddress = await deployer.deploy(l1Artifacts.registry, [ + clients.walletClient.account.address.toString(), + feeAssetAddress.toString(), + ]); + logger.verbose(`Deployed Registry at ${registryAddress}`); + + const governanceProposerAddress = await deployer.deploy(l1Artifacts.governanceProposer, [ + registryAddress.toString(), + args.governanceProposerQuorum, + args.governanceProposerRoundSize, + ]); + logger.verbose(`Deployed GovernanceProposer at ${governanceProposerAddress}`); + + // @note @LHerskind the assets are expected to be the same at some point, but for better + // configurability they are different for now. + const governanceAddress = await deployer.deploy(l1Artifacts.governance, [ + stakingAssetAddress.toString(), + governanceProposerAddress.toString(), + ]); + logger.verbose(`Deployed Governance at ${governanceAddress}`); + + const coinIssuerAddress = await deployer.deploy(l1Artifacts.coinIssuer, [ + feeAssetAddress.toString(), + 1n * 10n ** 18n, // @todo #8084 + governanceAddress.toString(), + ]); + logger.verbose(`Deployed CoinIssuer at ${coinIssuerAddress}`); + + const feeAsset = getContract({ + address: feeAssetAddress.toString(), + abi: l1Artifacts.feeAsset.contractAbi, + client: clients.publicClient, + }); + + logger.verbose(`Waiting for deployments to complete`); + await deployer.waitForDeployments(); + + if (args.acceleratedTestDeployments || !(await feeAsset.read.minters([coinIssuerAddress.toString()]))) { + const { txHash } = await deployer.sendTransaction({ + to: feeAssetAddress.toString(), + data: encodeFunctionData({ + abi: l1Artifacts.feeAsset.contractAbi, + functionName: 'addMinter', + args: [coinIssuerAddress.toString()], + }), + ...(args.acceleratedTestDeployments ? { gasLimit: 1_000_000n } : {}), + }); + logger.verbose(`Added coin issuer ${coinIssuerAddress} as minter on fee asset in ${txHash}`); + txHashes.push(txHash); + } + + const { txHash: setGovernanceTxHash } = await deployer.sendTransaction({ + to: registryAddress.toString(), + data: encodeFunctionData({ + abi: l1Artifacts.registry.contractAbi, + functionName: 'updateGovernance', + args: [governanceAddress.toString()], + }), + }); + + txHashes.push(setGovernanceTxHash); + + /* -------------------------------------------------------------------------- */ + /* CHEAT CODES START HERE */ + /* -------------------------------------------------------------------------- */ + + const feeAssetHandlerAddress = await deployer.deploy(l1Artifacts.feeAssetHandler, [ + clients.walletClient.account.address, + feeAssetAddress.toString(), + BigInt(1e18), + ]); + logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`); + + const { txHash } = await deployer.sendTransaction({ + to: feeAssetAddress.toString(), + data: encodeFunctionData({ + abi: l1Artifacts.feeAsset.contractAbi, + functionName: 'addMinter', + args: [feeAssetHandlerAddress.toString()], + }), + }); + logger.verbose(`Added fee asset handler ${feeAssetHandlerAddress} as minter on fee asset in ${txHash}`); + txHashes.push(txHash); + + // BEWARE: Down here we are NOT setting up the rollup nor the withdrawer here. + const stakingAssetHandlerAddress = await deployer.deploy(l1Artifacts.stakingAssetHandler, [ + clients.walletClient.account.address, + stakingAssetAddress.toString(), + EthAddress.ZERO.toString(), // rollup, + EthAddress.ZERO.toString(), // withdrawer, + args.minimumStake, // depositAmount, + BigInt(60 * 60 * 24), // mintInterval, + BigInt(10), // depositsPerMint, + [], // canAddValidator, + ]); + logger.verbose(`Deployed StakingAssetHandler at ${stakingAssetHandlerAddress}`); + + const { txHash: stakingMinterTxHash } = await deployer.sendTransaction({ + to: stakingAssetAddress.toString(), + data: encodeFunctionData({ + abi: l1Artifacts.stakingAsset.contractAbi, + functionName: 'addMinter', + args: [stakingAssetHandlerAddress.toString()], + }), + }); + logger.verbose( + `Added staking asset handler ${stakingAssetHandlerAddress} as minter on staking asset in ${stakingMinterTxHash}`, + ); + txHashes.push(stakingMinterTxHash); + + /* -------------------------------------------------------------------------- */ + /* CHEAT CODES END HERE */ + /* -------------------------------------------------------------------------- */ + + logger.verbose(`Waiting for deployments to complete`); + await deployer.waitForDeployments(); + await Promise.all(txHashes.map(txHash => clients.publicClient.waitForTransactionReceipt({ hash: txHash }))); + + logger.verbose(`Deployed shared contracts`); + + const registry = new RegistryContract(clients.publicClient, registryAddress); + + return { + feeAssetAddress, + feeAssetHandlerAddress, + stakingAssetAddress, + stakingAssetHandlerAddress, + registryAddress, + governanceAddress, + governanceProposerAddress, + coinIssuerAddress, + rewardDistributorAddress: await registry.getRewardDistributor(), + }; +}; + /** - * Deploys the rollup, slash factory, and the payload which can be used to make the rollup the canonical version. + * Deploys a new rollup, using the existing canonical version to derive certain values (addresses of assets etc). * @param clients - The L1 clients. * @param args - The deployment arguments. * @param registryAddress - The address of the registry. @@ -289,16 +452,11 @@ export const deployRollupForUpgrade = async ( const addresses = await RegistryContract.collectAddresses(clients.publicClient, registryAddress, 'canonical'); - const rollup = await deployRollup(clients, deployer, args, addresses, logger); - const payloadAddress = await deployUpgradePayload(deployer, { - registryAddress: addresses.registryAddress, - rollupAddress: EthAddress.fromString(rollup.address), - }); - const slashFactoryAddress = await deploySlashFactory(deployer, rollup.address, logger); + const { rollup, slashFactoryAddress } = await deployRollup(clients, deployer, args, addresses, logger); await deployer.waitForDeployments(); - return { rollup, payloadAddress, slashFactoryAddress }; + return { rollup, slashFactoryAddress }; }; export const deploySlashFactory = async (deployer: L1Deployer, rollupAddress: Hex, logger: Logger) => { @@ -319,13 +477,21 @@ export const deployUpgradePayload = async ( return payloadAddress; }; +/** + * Deploys a new rollup contract, funds and initializes the fee juice portal, and initializes the validator set. + */ export const deployRollup = async ( clients: L1Clients, deployer: L1Deployer, args: DeployL1ContractsArgs, - addresses: Pick, + addresses: Pick< + L1ContractAddresses, + 'feeJuiceAddress' | 'registryAddress' | 'rewardDistributorAddress' | 'stakingAssetAddress' + >, logger: Logger, -): Promise => { +) => { + const txHashes: Hex[] = []; + const rollupConfigArgs = { aztecSlotDuration: args.aztecSlotDuration, aztecEpochDuration: args.aztecEpochDuration, @@ -345,7 +511,7 @@ export const deployRollup = async ( }; logger.verbose(`Rollup config args`, rollupConfigArgs); const rollupArgs = [ - addresses.feeJuicePortalAddress.toString(), + addresses.feeJuiceAddress.toString(), addresses.rewardDistributorAddress.toString(), addresses.stakingAssetAddress.toString(), clients.walletClient.account.address.toString(), @@ -356,6 +522,8 @@ export const deployRollup = async ( const rollupAddress = await deployer.deploy(l1Artifacts.rollup, rollupArgs); logger.verbose(`Deployed Rollup at ${rollupAddress}`, rollupConfigArgs); + const rollupContract = new RollupContract(clients.publicClient, rollupAddress); + await deployer.waitForDeployments(); logger.verbose(`All core contracts have been deployed`); @@ -371,10 +539,149 @@ export const deployRollup = async ( ); } - return new RollupContract(clients.publicClient, rollupAddress); + const feeJuicePortalAddress = await rollupContract.getFeeJuicePortal(); + + // @note This value MUST match what is in `constants.nr`. It is currently specified here instead of just importing + // because there is circular dependency hell. This is a temporary solution. #3342 + // @todo #8084 + // fund the portal contract with Fee Juice + const FEE_JUICE_INITIAL_MINT = 200000000000000000000000n; + + // In fast mode, use the L1TxUtils to send transactions with nonce management + const { txHash: mintTxHash } = await deployer.sendTransaction({ + to: addresses.feeJuiceAddress.toString(), + data: encodeFunctionData({ + abi: l1Artifacts.feeAsset.contractAbi, + functionName: 'mint', + args: [feeJuicePortalAddress.toString(), FEE_JUICE_INITIAL_MINT], + }), + }); + logger.verbose(`Funding fee juice portal contract with fee juice in ${mintTxHash} (accelerated test deployments)`); + txHashes.push(mintTxHash); + + // @note This is used to ensure we fully wait for the transaction when running against a real chain + // otherwise we execute subsequent transactions too soon + if (!args.acceleratedTestDeployments) { + await clients.publicClient.waitForTransactionReceipt({ hash: mintTxHash }); + logger.verbose(`Funding fee juice portal contract with fee juice in ${mintTxHash}`); + } + + const feeJuicePortal = getContract({ + address: getAddress(feeJuicePortalAddress.toString()), + abi: l1Artifacts.feeJuicePortal.contractAbi, + client: clients.publicClient, + }); + + // Check if portal needs initialization + let needsInitialization = args.acceleratedTestDeployments; + if (!args.acceleratedTestDeployments) { + // Only check if not in fast mode and not already known to need initialization + needsInitialization = !(await feeJuicePortal.read.initialized()); + } + if (needsInitialization) { + const { txHash: initPortalTxHash } = await deployer.sendTransaction({ + to: feeJuicePortalAddress.toString(), + data: encodeFunctionData({ + abi: l1Artifacts.feeJuicePortal.contractAbi, + functionName: 'initialize', + args: [], + }), + }); + txHashes.push(initPortalTxHash); + logger.verbose(`Fee juice portal initializing in tx ${initPortalTxHash}`); + } else { + logger.verbose(`Fee juice portal is already initialized`); + } + + logger.verbose( + `Initialized Fee Juice Portal at ${feeJuicePortalAddress} to bridge between L1 ${addresses.feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`, + ); + + const slashFactoryAddress = await deployer.deploy(l1Artifacts.slashFactory, [rollupAddress.toString()]); + logger.verbose(`Deployed SlashFactory at ${slashFactoryAddress}`); + + // We need to call a function on the registry to set the various contract addresses. + const registryContract = getContract({ + address: getAddress(addresses.registryAddress.toString()), + abi: l1Artifacts.registry.contractAbi, + client: clients.walletClient, + }); + + // Only if we are the owner will we be sending these transactions + if ((await registryContract.read.owner()) === getAddress(clients.walletClient.account.address)) { + const version = await rollupContract.getVersion(); + try { + const retrievedRollupAddress = await registryContract.read.getRollup([version]); + logger.verbose(`Rollup ${retrievedRollupAddress} already exists in registry`); + } catch (e) { + const { txHash: addRollupTxHash } = await deployer.sendTransaction({ + to: addresses.registryAddress.toString(), + data: encodeFunctionData({ + abi: l1Artifacts.registry.contractAbi, + functionName: 'addRollup', + args: [getAddress(rollupContract.address)], + }), + }); + logger.verbose( + `Adding rollup ${rollupContract.address} to registry ${addresses.registryAddress} in tx ${addRollupTxHash}`, + ); + + txHashes.push(addRollupTxHash); + } + } else { + logger.verbose(`Not the owner of the registry, skipping rollup addition`); + } + + await deployer.waitForDeployments(); + await Promise.all(txHashes.map(txHash => clients.publicClient.waitForTransactionReceipt({ hash: txHash }))); + logger.verbose(`Rollup deployed`); + + return { rollup: rollupContract, slashFactoryAddress }; }; -/** +export const handoverToGovernance = async ( + clients: L1Clients, + deployer: L1Deployer, + registryAddress: EthAddress, + governanceAddress: EthAddress, + logger: Logger, + acceleratedTestDeployments: boolean | undefined, +) => { + // We need to call a function on the registry to set the various contract addresses. + const registryContract = getContract({ + address: getAddress(registryAddress.toString()), + abi: l1Artifacts.registry.contractAbi, + client: clients.walletClient, + }); + + const txHashes: Hex[] = []; + + // If the owner is not the Governance contract, transfer ownership to the Governance contract + if ( + acceleratedTestDeployments || + (await registryContract.read.owner()) !== getAddress(governanceAddress.toString()) + ) { + // TODO(md): add send transaction to the deployer such that we do not need to manage tx hashes here + const { txHash: transferOwnershipTxHash } = await deployer.sendTransaction({ + to: registryAddress.toString(), + data: encodeFunctionData({ + abi: l1Artifacts.registry.contractAbi, + functionName: 'transferOwnership', + args: [getAddress(governanceAddress.toString())], + }), + }); + logger.verbose( + `Transferring the ownership of the registry contract at ${registryAddress} to the Governance ${governanceAddress} in tx ${transferOwnershipTxHash}`, + ); + txHashes.push(transferOwnershipTxHash); + } + + // Wait for all actions to be mined + await deployer.waitForDeployments(); + await Promise.all(txHashes.map(txHash => clients.publicClient.waitForTransactionReceipt({ hash: txHash }))); +}; + +/* * Initialize the validator set for the rollup using a cheat function. * @note This function will only be used when the chain is local anvil node soon (#12050) * @@ -544,7 +851,6 @@ export const deployL1Contracts = async ( logger.verbose(`Deploying contracts from ${account.address.toString()}`); - // Governance stuff const deployer = new L1Deployer( walletClient, publicClient, @@ -554,209 +860,24 @@ export const deployL1Contracts = async ( txUtilsConfig, ); - const registryAddress = await deployer.deploy(l1Artifacts.registry, [account.address.toString()]); - logger.verbose(`Deployed Registry at ${registryAddress}`); - - const feeAssetAddress = await deployer.deploy(l1Artifacts.feeAsset, ['FeeJuice', 'FEE', account.address.toString()]); - logger.verbose(`Deployed Fee Juice at ${feeAssetAddress}`); - - const stakingAssetAddress = await deployer.deploy(l1Artifacts.stakingAsset, [ - 'Staking', - 'STK', - account.address.toString(), - ]); - logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`); - - const governanceProposerAddress = await deployer.deploy(l1Artifacts.governanceProposer, [ - registryAddress.toString(), - args.governanceProposerQuorum, - args.governanceProposerRoundSize, - ]); - logger.verbose(`Deployed GovernanceProposer at ${governanceProposerAddress}`); - - // @note @LHerskind the assets are expected to be the same at some point, but for better - // configurability they are different for now. - const governanceAddress = await deployer.deploy(l1Artifacts.governance, [ - stakingAssetAddress.toString(), - governanceProposerAddress.toString(), - ]); - logger.verbose(`Deployed Governance at ${governanceAddress}`); - - const coinIssuerAddress = await deployer.deploy(l1Artifacts.coinIssuer, [ - feeAssetAddress.toString(), - 1n * 10n ** 18n, // @todo #8084 - governanceAddress.toString(), - ]); - logger.verbose(`Deployed CoinIssuer at ${coinIssuerAddress}`); - - const rewardDistributorAddress = await deployer.deploy(l1Artifacts.rewardDistributor, [ - feeAssetAddress.toString(), - registryAddress.toString(), - governanceAddress.toString(), - ]); - logger.verbose(`Deployed RewardDistributor at ${rewardDistributorAddress}`); - - const feeJuicePortalAddress = await deployer.deploy(l1Artifacts.feeJuicePortal, [ - registryAddress.toString(), - feeAssetAddress.toString(), - args.l2FeeJuiceAddress.toString(), - ]); - logger.verbose(`Deployed Fee Juice Portal at ${feeJuicePortalAddress}`); - - logger.verbose(`Waiting for governance contracts to be deployed`); - await deployer.waitForDeployments(); - logger.verbose(`All governance contracts deployed`); - - const feeJuicePortal = getContract({ - address: feeJuicePortalAddress.toString(), - abi: l1Artifacts.feeJuicePortal.contractAbi, - client: walletClient, - }); - - const feeAsset = getContract({ - address: feeAssetAddress.toString(), - abi: l1Artifacts.feeAsset.contractAbi, - client: walletClient, - }); - // Transaction hashes to await - const txHashes: Hex[] = []; - - const { feeAssetHandlerAddress, txHash: feeAssetHandlerTxHash } = await cheat_initializeFeeAssetHandler( + const { feeAssetAddress, feeAssetHandlerAddress, stakingAssetAddress, registryAddress, rewardDistributorAddress } = + await deploySharedContracts(clients, deployer, args, logger); + const { rollup, slashFactoryAddress } = await deployRollup( clients, deployer, - feeAssetAddress, - logger, - ); - txHashes.push(feeAssetHandlerTxHash); - - if (args.acceleratedTestDeployments || !(await feeAsset.read.minters([coinIssuerAddress.toString()]))) { - const { txHash } = await deployer.sendTransaction({ - to: feeAssetAddress.toString(), - data: encodeFunctionData({ - abi: l1Artifacts.feeAsset.contractAbi, - functionName: 'addMinter', - args: [coinIssuerAddress.toString()], - }), - }); - logger.verbose(`Added coin issuer ${coinIssuerAddress} as minter on fee asset in ${txHash}`); - txHashes.push(txHash); - } - - // @note This value MUST match what is in `constants.nr`. It is currently specified here instead of just importing - // because there is circular dependency hell. This is a temporary solution. #3342 - // @todo #8084 - // fund the portal contract with Fee Juice - const FEE_JUICE_INITIAL_MINT = 200000000000000000000000n; - - // In fast mode, use the L1TxUtils to send transactions with nonce management - const { txHash: mintTxHash } = await deployer.sendTransaction({ - to: feeAssetAddress.toString(), - data: encodeFunctionData({ - abi: l1Artifacts.feeAsset.contractAbi, - functionName: 'mint', - args: [feeJuicePortalAddress.toString(), FEE_JUICE_INITIAL_MINT], - }), - }); - logger.verbose(`Funding fee juice portal contract with fee juice in ${mintTxHash} (accelerated test deployments)`); - txHashes.push(mintTxHash); - - // @note This is used to ensure we fully wait for the transaction when running against a real chain - // otherwise we execute subsequent transactions too soon - if (!args.acceleratedTestDeployments) { - await publicClient.waitForTransactionReceipt({ hash: mintTxHash }); - logger.verbose(`Funding fee juice portal contract with fee juice in ${mintTxHash}`); - } - - // Check if portal needs initialization - let needsInitialization = args.acceleratedTestDeployments; - if (!args.acceleratedTestDeployments) { - // Only check if not in fast mode and not already known to need initialization - needsInitialization = !(await feeJuicePortal.read.initialized()); - } - if (needsInitialization) { - const { txHash: initPortalTxHash } = await deployer.sendTransaction({ - to: feeJuicePortalAddress.toString(), - data: encodeFunctionData({ - abi: l1Artifacts.feeJuicePortal.contractAbi, - functionName: 'initialize', - args: [], - }), - }); - - txHashes.push(initPortalTxHash); - logger.verbose(`Fee juice portal initializing in tx ${initPortalTxHash}`); - } else { - logger.verbose(`Fee juice portal is already initialized`); - } - logger.verbose( - `Initialized Fee Juice Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeAssetAddress} to L2 ${args.l2FeeJuiceAddress}`, - ); - - const rollup = await deployRollup( + args, { - walletClient, - publicClient, + feeJuiceAddress: feeAssetAddress, + registryAddress, + rewardDistributorAddress, + stakingAssetAddress, }, - deployer, - args, - { feeJuicePortalAddress, rewardDistributorAddress, stakingAssetAddress }, logger, ); - const slashFactoryAddress = await deploySlashFactory(deployer, rollup.address, logger); logger.verbose('Waiting for rollup and slash factory to be deployed'); await deployer.waitForDeployments(); - logger.verbose(`Rollup and slash factory deployed`); - - // We need to call a function on the registry to set the various contract addresses. - const registryContract = getContract({ - address: getAddress(registryAddress.toString()), - abi: l1Artifacts.registry.contractAbi, - client: walletClient, - }); - if ( - args.acceleratedTestDeployments || - !(await registryContract.read.isRollupRegistered([getAddress(rollup.address.toString())])) - ) { - const { txHash: upgradeTxHash } = await deployer.sendTransaction({ - to: registryAddress.toString(), - data: encodeFunctionData({ - abi: l1Artifacts.registry.contractAbi, - functionName: 'upgrade', - args: [getAddress(rollup.address.toString())], - }), - }); - logger.verbose( - `Upgrading registry contract at ${registryAddress} to rollup ${rollup.address} in tx ${upgradeTxHash}`, - ); - txHashes.push(upgradeTxHash); - } else { - logger.verbose(`Registry ${registryAddress} has already registered rollup ${rollup.address}`); - } - - // If the owner is not the Governance contract, transfer ownership to the Governance contract - if ( - args.acceleratedTestDeployments || - (await registryContract.read.owner()) !== getAddress(governanceAddress.toString()) - ) { - // TODO(md): add send transaction to the deployer such that we do not need to manage tx hashes here - const { txHash: transferOwnershipTxHash } = await deployer.sendTransaction({ - to: registryAddress.toString(), - data: encodeFunctionData({ - abi: l1Artifacts.registry.contractAbi, - functionName: 'transferOwnership', - args: [getAddress(governanceAddress.toString())], - }), - }); - logger.verbose( - `Transferring the ownership of the registry contract at ${registryAddress} to the Governance ${governanceAddress} in tx ${transferOwnershipTxHash}`, - ); - txHashes.push(transferOwnershipTxHash); - } - - // Wait for all actions to be mined - await Promise.all(txHashes.map(txHash => publicClient.waitForTransactionReceipt({ hash: txHash }))); logger.verbose(`All transactions for L1 deployment have been mined`); const l1Contracts = await RegistryContract.collectAddresses(publicClient, registryAddress, 'canonical'); @@ -796,7 +917,7 @@ export const deployL1Contracts = async ( }; }; -class L1Deployer { +export class L1Deployer { private salt: Hex | undefined; private txHashes: Hex[] = []; public readonly l1TxUtils: L1TxUtils; diff --git a/yarn-project/ethereum/src/l1_contract_addresses.ts b/yarn-project/ethereum/src/l1_contract_addresses.ts index 4b625ca5ebc4..eab987281cf3 100644 --- a/yarn-project/ethereum/src/l1_contract_addresses.ts +++ b/yarn-project/ethereum/src/l1_contract_addresses.ts @@ -26,7 +26,11 @@ export const L1ContractsNames = [ /** Provides the directory of current L1 contract addresses */ export type L1ContractAddresses = { [K in (typeof L1ContractsNames)[number]]: EthAddress; -} & { slashFactoryAddress?: EthAddress | undefined; feeAssetHandlerAddress?: EthAddress | undefined }; +} & { + slashFactoryAddress?: EthAddress | undefined; + feeAssetHandlerAddress?: EthAddress | undefined; + stakingAssetHandlerAddress?: EthAddress | undefined; +}; export const L1ContractAddressesSchema = z.object({ rollupAddress: schemas.EthAddress, @@ -42,6 +46,7 @@ export const L1ContractAddressesSchema = z.object({ governanceAddress: schemas.EthAddress, slashFactoryAddress: schemas.EthAddress.optional(), feeAssetHandlerAddress: schemas.EthAddress.optional(), + stakingAssetHandlerAddress: schemas.EthAddress.optional(), }) satisfies ZodFor; const parseEnv = (val: string) => EthAddress.fromString(val); @@ -112,4 +117,9 @@ export const l1ContractAddressesMapping: ConfigMappingsType description: 'The deployed L1 feeAssetHandler contract address', parseEnv, }, + stakingAssetHandlerAddress: { + env: 'STAKING_ASSET_HANDLER_CONTRACT_ADDRESS', + description: 'The deployed L1 stakingAssetHandler contract address', + parseEnv, + }, }; diff --git a/yarn-project/foundation/src/config/env_var.ts b/yarn-project/foundation/src/config/env_var.ts index fa1bfb3dd31d..a0ff8408fae5 100644 --- a/yarn-project/foundation/src/config/env_var.ts +++ b/yarn-project/foundation/src/config/env_var.ts @@ -164,6 +164,7 @@ export type EnvVar = | 'SEQ_MAX_L1_TX_INCLUSION_TIME_INTO_SLOT' | 'SLASH_FACTORY_CONTRACT_ADDRESS' | 'STAKING_ASSET_CONTRACT_ADDRESS' + | 'STAKING_ASSET_HANDLER_CONTRACT_ADDRESS' | 'SYNC_MODE' | 'SYNC_SNAPSHOTS_URL' | 'REWARD_DISTRIBUTOR_CONTRACT_ADDRESS' diff --git a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh index 17c85ae26f31..e1665063d747 100755 --- a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh +++ b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh @@ -33,6 +33,7 @@ contracts=( "Slasher" "SlashFactory" "SlashingProposer" + "StakingAssetHandler" "TestERC20" "TokenPortal" "UniswapPortal"