Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions l1-contracts/src/core/RollupCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
// 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,
Expand Down Expand Up @@ -98,14 +96,17 @@ contract RollupCore is
)
);
rollupStore.config.version = version;
rollupStore.config.inbox =
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)
IInbox inbox = IInbox(
address(new Inbox(address(this), _feeAsset, version, Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT))
);

rollupStore.config.inbox = inbox;

rollupStore.config.outbox = IOutbox(address(new Outbox(address(this), version)));

rollupStore.config.feeAssetPortal = IFeeJuicePortal(inbox.getFeeAssetPortal());

FeeLib.initialize(_config.manaTarget, _config.provingCostPerMana);
}

Expand Down
1 change: 0 additions & 1 deletion l1-contracts/src/core/interfaces/IFeeJuicePortal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ interface IFeeJuicePortal {
);
event FeesDistributed(address indexed to, uint256 amount);

function initialize() external;
function distributeFees(address _to, uint256 _amount) external;
function depositToAztecPublic(bytes32 _to, uint256 _amount, bytes32 _secretHash)
external
Expand Down
2 changes: 2 additions & 0 deletions l1-contracts/src/core/interfaces/messagebridge/IInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ interface IInbox {
function consume(uint256 _toConsume) external returns (bytes32);
// docs:end:consume

function getFeeAssetPortal() external view returns (address);

function getRoot(uint256 _blockNumber) external view returns (bytes32);
}
1 change: 0 additions & 1 deletion l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ library Constants {
20646204262468251631976884937192820660867507115079672078981654411421834866549;
uint256 internal constant GENESIS_ARCHIVE_ROOT =
1002640778211850180189505934749257244705296832326768971348723156503780793518;
uint256 internal constant FEE_JUICE_INITIAL_MINT = 200000000000000000000000;
uint256 internal constant PUBLIC_DISPATCH_SELECTOR = 3578010381;
uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 3000;
uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,13 @@ contract FeeJuicePortal is IFeeJuicePortal {
IERC20 public immutable UNDERLYING;
uint256 public immutable VERSION;

bool public initialized;

constructor(IRollup _rollup, IERC20 _underlying, IInbox _inbox, uint256 _version) {
ROLLUP = _rollup;
INBOX = _inbox;
UNDERLYING = _underlying;
VERSION = _version;
}

/**
* @notice Initialize the FeeJuicePortal
*
* @dev This function is only callable by the owner of the contract and only once
*
* @dev Must be funded with FEE_JUICE_INITIAL_MINT tokens before initialization to
* ensure that the L2 contract is funded and able to pay for its deployment.
*/
function initialize() external override(IFeeJuicePortal) {
require(!initialized, Errors.FeeJuicePortal__AlreadyInitialized());

uint256 balance = UNDERLYING.balanceOf(address(this));
if (balance < Constants.FEE_JUICE_INITIAL_MINT) {
UNDERLYING.safeTransferFrom(
msg.sender, address(this), Constants.FEE_JUICE_INITIAL_MINT - balance
);
}
initialized = true;
}

/**
* @notice Deposit funds into the portal and adds an L2 message which can only be consumed publicly on Aztec
* @param _to - The aztec address of the recipient
Expand Down
22 changes: 20 additions & 2 deletions l1-contracts/src/core/messagebridge/Inbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

import {IRollup} from "@aztec/core/interfaces/IRollup.sol";
import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {FrontierLib} from "@aztec/core/libraries/crypto/FrontierLib.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 {FeeJuicePortal} from "@aztec/core/messagebridge/FeeJuicePortal.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";

/**
* @title Inbox
Expand All @@ -21,6 +25,7 @@ contract Inbox is IInbox {

address public immutable ROLLUP;
uint256 public immutable VERSION;
address public immutable FEE_ASSET_PORTAL;

uint256 internal immutable HEIGHT;
uint256 internal immutable SIZE;
Expand All @@ -38,7 +43,7 @@ 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 _version, uint256 _height) {
constructor(address _rollup, IERC20 _feeAsset, uint256 _version, uint256 _height) {
ROLLUP = _rollup;
VERSION = _version;

Expand All @@ -47,6 +52,9 @@ contract Inbox is IInbox {

forest.initialize(_height);
EMPTY_ROOT = trees[inProgress].root(forest, HEIGHT, SIZE);

FEE_ASSET_PORTAL =
address(new FeeJuicePortal(IRollup(_rollup), _feeAsset, IInbox(this), VERSION));
}

/**
Expand Down Expand Up @@ -90,8 +98,14 @@ contract Inbox is IInbox {
// trees are constant size so global index = tree number * size + subtree index
uint256 index = (inProgress - Constants.INITIAL_L2_BLOCK_NUM) * SIZE + currentTree.nextIndex;

// If the sender is the fee asset portal, we use a magic address to simpler have it initialized at genesis.
// We assume that no-one will know the private key for this address and that the precompile won't change to
// make calls into arbitrary contracts.
address senderAddress =
msg.sender == FEE_ASSET_PORTAL ? address(uint160(Constants.FEE_JUICE_ADDRESS)) : msg.sender;

DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({
sender: DataStructures.L1Actor(msg.sender, block.chainid),
sender: DataStructures.L1Actor(senderAddress, block.chainid),
recipient: _recipient,
content: _content,
secretHash: _secretHash,
Expand Down Expand Up @@ -134,6 +148,10 @@ contract Inbox is IInbox {
return root;
}

function getFeeAssetPortal() external view override(IInbox) returns (address) {
return FEE_ASSET_PORTAL;
}

function getRoot(uint256 _blockNumber) external view override(IInbox) returns (bytes32) {
return trees[_blockNumber].root(forest, HEIGHT, SIZE);
}
Expand Down
2 changes: 0 additions & 2 deletions l1-contracts/src/mock/MockFeeJuicePortal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ contract MockFeeJuicePortal is IFeeJuicePortal {
UNDERLYING = new TestERC20("test", "TEST", msg.sender);
}

function initialize() external override(IFeeJuicePortal) {}

function distributeFees(address, uint256) external override(IFeeJuicePortal) {}

function depositToAztecPublic(bytes32, uint256, bytes32)
Expand Down
6 changes: 4 additions & 2 deletions l1-contracts/test/Inbox.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
pragma solidity >=0.8.27;

import {Test} from "forge-std/Test.sol";

import {TestERC20} from "src/mock/TestERC20.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol";
import {InboxHarness} from "./harnesses/InboxHarness.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
Expand All @@ -26,7 +27,8 @@ contract InboxTest is Test {

function setUp() public {
address rollup = address(this);
inbox = new InboxHarness(rollup, version, HEIGHT);
IERC20 feeAsset = new TestERC20("Fee Asset", "FA", address(this));
inbox = new InboxHarness(rollup, feeAsset, version, HEIGHT);
emptyTreeRoot = inbox.getEmptyRoot();
}

Expand Down
8 changes: 4 additions & 4 deletions l1-contracts/test/MultiProof.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {DecoderBase} from "./base/DecoderBase.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";

import {Registry} from "@aztec/governance/Registry.sol";
import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol";
import {FeeJuicePortal} from "@aztec/core/messagebridge/FeeJuicePortal.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";
import {TestConstants} from "./harnesses/TestConstants.sol";
import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol";
Expand Down Expand Up @@ -90,9 +90,6 @@ contract MultiProofTest is RollupBase {

feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal()));

testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT);
feeJuicePortal.initialize();

registry.addRollup(IRollup(address(rollup)));

_;
Expand Down Expand Up @@ -137,6 +134,9 @@ contract MultiProofTest is RollupBase {
address alice = address(bytes20("alice"));
address bob = address(bytes20("bob"));

// We need to mint some fee asset to the portal to cover the 30M mana spent.
deal(address(testERC20), address(feeJuicePortal), 30e6 * 1e18);

_proposeBlock("mixed_block_1", 1, 15e6);
_proposeBlock("mixed_block_2", 2, 15e6);

Expand Down
8 changes: 4 additions & 4 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
FeeAssetPerEthE9,
PublicInputArgs
} from "@aztec/core/interfaces/IRollup.sol";
import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol";
import {FeeJuicePortal} from "@aztec/core/messagebridge/FeeJuicePortal.sol";
import {NaiveMerkle} from "./merkle/Naive.sol";
import {MerkleTestUtil} from "./merkle/TestUtil.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";
Expand Down Expand Up @@ -108,9 +108,6 @@ contract RollupTest is RollupBase {

feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal()));

testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT);
feeJuicePortal.initialize();

merkleTestUtil = new MerkleTestUtil();
_;
}
Expand Down Expand Up @@ -349,6 +346,9 @@ contract RollupTest is RollupBase {
}

function testProvingFeeUpdates() public setUpFor("mixed_block_1") {
// We need to mint some fee asset to the portal to cover the 2M mana spent.
deal(address(testERC20), address(feeJuicePortal), 2e6 * 1e18);

rollup.setProvingCostPerMana(EthValue.wrap(1000));
_proposeBlock("mixed_block_1", 1, 1e6);

Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/test/benchmark/happy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
PublicInputArgs,
RollupConfigInput
} from "@aztec/core/interfaces/IRollup.sol";
import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol";
import {FeeJuicePortal} from "@aztec/core/messagebridge/FeeJuicePortal.sol";
import {NaiveMerkle} from "../merkle/Naive.sol";
import {MerkleTestUtil} from "../merkle/TestUtil.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";
Expand Down
10 changes: 6 additions & 4 deletions l1-contracts/test/fee_portal/depositToAztecPublic.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ 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";
import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol";
import {FeeJuicePortal} from "@aztec/core/messagebridge/FeeJuicePortal.sol";
import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol";
Expand All @@ -27,6 +27,8 @@ contract DepositToAztecPublic is Test {
Rollup internal rollup;
RewardDistributor internal rewardDistributor;

address internal constant MAGIC_FEE_JUICE_ADDRESS = address(uint160(Constants.FEE_JUICE_ADDRESS));

function setUp() public {
token = new TestERC20("test", "TEST", address(this));
registry = new Registry(OWNER, token);
Expand All @@ -42,8 +44,6 @@ contract DepositToAztecPublic is Test {
);

feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal()));
token.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT);
feeJuicePortal.initialize();

vm.prank(OWNER);
registry.addRollup(IRollup(address(rollup)));
Expand Down Expand Up @@ -79,8 +79,10 @@ contract DepositToAztecPublic 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.
// Separately, NOTE that the sender is the MAGIC_FEE_JUICE_ADDRESS, not the feeJuicePortal address in
// this special case.
DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({
sender: DataStructures.L1Actor(address(feeJuicePortal), block.chainid),
sender: DataStructures.L1Actor(MAGIC_FEE_JUICE_ADDRESS, block.chainid),
recipient: DataStructures.L2Actor(feeJuicePortal.L2_TOKEN_ADDRESS(), rollup.getVersion()),
content: Hash.sha256ToField(abi.encodeWithSignature("claim(bytes32,uint256)", to, amount)),
secretHash: secretHash,
Expand Down
21 changes: 10 additions & 11 deletions l1-contracts/test/fee_portal/distributeFees.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ 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";
import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol";
import {FeeJuicePortal} from "@aztec/core/messagebridge/FeeJuicePortal.sol";
import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol";
Expand Down Expand Up @@ -41,8 +41,6 @@ contract DistributeFees is Test {
);

feeJuicePortal = FeeJuicePortal(address(rollup.getFeeAssetPortal()));
token.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT);
feeJuicePortal.initialize();

vm.prank(OWNER);
registry.addRollup(IRollup(address(rollup)));
Expand All @@ -63,13 +61,10 @@ contract DistributeFees is Test {
vm.prank(address(rollup));
vm.expectRevert(
abi.encodeWithSelector(
IERC20Errors.ERC20InsufficientBalance.selector,
address(feeJuicePortal),
Constants.FEE_JUICE_INITIAL_MINT,
Constants.FEE_JUICE_INITIAL_MINT + 1
IERC20Errors.ERC20InsufficientBalance.selector, address(feeJuicePortal), 0, 0 + 1
)
);
feeJuicePortal.distributeFees(address(this), Constants.FEE_JUICE_INITIAL_MINT + 1);
feeJuicePortal.distributeFees(address(this), 1);
}

function test_GivenSufficientBalance() external givenTheCallerIsTheCanonicalRollup {
Expand All @@ -78,11 +73,15 @@ contract DistributeFees is Test {

assertEq(token.balanceOf(address(this)), 0);

uint256 initialBalance = 10e18;

deal(address(token), address(feeJuicePortal), initialBalance);

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);
emit IFeeJuicePortal.FeesDistributed(address(this), initialBalance);
feeJuicePortal.distributeFees(address(this), initialBalance);

assertEq(token.balanceOf(address(this)), Constants.FEE_JUICE_INITIAL_MINT);
assertEq(token.balanceOf(address(this)), initialBalance);
}
}
2 changes: 1 addition & 1 deletion l1-contracts/test/fees/FeeRollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
PublicInputArgs,
RollupConfigInput
} from "@aztec/core/interfaces/IRollup.sol";
import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol";
import {FeeJuicePortal} from "@aztec/core/messagebridge/FeeJuicePortal.sol";
import {NaiveMerkle} from "../merkle/Naive.sol";
import {MerkleTestUtil} from "../merkle/TestUtil.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";
Expand Down
6 changes: 4 additions & 2 deletions l1-contracts/test/harnesses/InboxHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
pragma solidity >=0.8.27;

import {Inbox} from "@aztec/core/messagebridge/Inbox.sol";

import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {FrontierLib} from "@aztec/core/libraries/crypto/FrontierLib.sol";

contract InboxHarness is Inbox {
using FrontierLib for FrontierLib.Tree;

constructor(address _rollup, uint256 _version, uint256 _height) Inbox(_rollup, _version, _height) {}
constructor(address _rollup, IERC20 _feeAsset, uint256 _version, uint256 _height)
Inbox(_rollup, _feeAsset, _version, _height)
{}

function getSize() external view returns (uint256) {
return SIZE;
Expand Down
4 changes: 1 addition & 3 deletions l1-contracts/test/ignition.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {DecoderBase} from "./base/DecoderBase.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";

import {Registry} from "@aztec/governance/Registry.sol";
import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol";
import {FeeJuicePortal} from "@aztec/core/messagebridge/FeeJuicePortal.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";
import {TestConstants} from "./harnesses/TestConstants.sol";
import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol";
Expand Down Expand Up @@ -93,8 +93,6 @@ contract IgnitionTest is RollupBase {
);

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);

Expand Down
Loading