Skip to content

feat: RollupPassage contract #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 15, 2024
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
10 changes: 7 additions & 3 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ OrdersTest:test_fill_underflowETH() (gas: 115281)
OrdersTest:test_initiate_ERC20() (gas: 81435)
OrdersTest:test_initiate_ETH() (gas: 44949)
OrdersTest:test_initiate_both() (gas: 118677)
OrdersTest:test_initiate_multiERC20() (gas: 688417)
OrdersTest:test_initiate_multiERC20() (gas: 722408)
OrdersTest:test_initiate_multiETH() (gas: 75304)
OrdersTest:test_onlyBuilder() (gas: 12815)
OrdersTest:test_orderExpired() (gas: 27956)
OrdersTest:test_sweepERC20() (gas: 60402)
OrdersTest:test_sweepERC20() (gas: 60446)
OrdersTest:test_sweepETH() (gas: 81940)
OrdersTest:test_underflowETH() (gas: 63528)
PassageTest:test_configureEnter() (gas: 82311)
Expand All @@ -26,7 +26,11 @@ PassageTest:test_receive() (gas: 21384)
PassageTest:test_setUp() (gas: 16968)
PassageTest:test_transact() (gas: 58562)
PassageTest:test_transact_defaultChain() (gas: 57475)
PassageTest:test_withdraw() (gas: 59033)
PassageTest:test_withdraw() (gas: 59166)
RollupPassageTest:test_exit() (gas: 22347)
RollupPassageTest:test_exitToken() (gas: 50183)
RollupPassageTest:test_fallback() (gas: 19883)
RollupPassageTest:test_receive() (gas: 19844)
ZenithTest:test_addSequencer() (gas: 88121)
ZenithTest:test_badSignature() (gas: 37241)
ZenithTest:test_incorrectHostBlock() (gas: 35086)
Expand Down
5 changes: 3 additions & 2 deletions script/Zenith.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.24;

import {Script} from "forge-std/Script.sol";
import {Zenith} from "../src/Zenith.sol";
import {Passage} from "../src/Passage.sol";
import {Passage, RollupPassage} from "../src/Passage.sol";
import {HostOrders, RollupOrders} from "../src/Orders.sol";

contract ZenithScript is Script {
Expand All @@ -23,8 +23,9 @@ contract ZenithScript is Script {

// deploy:
// forge script ZenithScript --sig "deployL2()" --rpc-url $L2_RPC_URL --private-key $PRIVATE_KEY --broadcast
function deployL2() public returns (RollupOrders m) {
function deployL2() public returns (RollupPassage p, RollupOrders m) {
vm.startBroadcast();
p = new RollupPassage();
m = new RollupOrders();
}

Expand Down
47 changes: 45 additions & 2 deletions src/Passage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
pragma solidity ^0.8.24;

import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";

/// @notice A contract deployed to Host chain that allows tokens to enter the rollup,
/// and enables Builders to fulfill requests to exchange tokens on the Rollup for tokens on the Host.
/// @notice A contract deployed to Host chain that allows tokens to enter the rollup.
contract Passage {
/// @notice The chainId of rollup that Ether will be sent to by default when entering the rollup via fallback() or receive().
uint256 public immutable defaultRollupChainId;
Expand Down Expand Up @@ -178,3 +178,46 @@ contract Passage {
emit EnterConfigured(token, _canEnter);
}
}

/// @notice Enables tokens to Exit the rollup.
contract RollupPassage {
/// @notice Emitted when native Ether exits the rollup.
/// @param hostRecipient - The *requested* recipient of tokens on the host chain.
/// @param amount - The amount of Ether exiting the rollup.
event Exit(address indexed hostRecipient, uint256 amount);

/// @notice Emitted when ERC20 tokens exit the rollup.
/// @param hostRecipient - The *requested* recipient of tokens on the host chain.
/// @param token - The token exiting the rollup.
/// @param amount - The amount of ERC20s exiting the rollup.
event ExitToken(address indexed hostRecipient, address indexed token, uint256 amount);

/// @notice Allows native Ether to exit the rollup by being sent directly to the contract.
fallback() external payable {
exit(msg.sender);
}

/// @notice Allows native Ether to exit the rollup by being sent directly to the contract.
receive() external payable {
exit(msg.sender);
}

/// @notice Allows native Ether to exit the rollup.
/// @param hostRecipient - The *requested* recipient of tokens on the host chain.
/// @custom:emits Exit indicating the amount of Ether that was locked on the rollup & the requested host recipient.
function exit(address hostRecipient) public payable {
if (msg.value == 0) return;
emit Exit(hostRecipient, msg.value);
}

/// @notice Allows ERC20 tokens to exit the rollup.
/// @param hostRecipient - The *requested* recipient of tokens on the host chain.
/// @param token - The rollup address of the token exiting the rollup.
/// @param amount - The amount of tokens exiting the rollup.
function exitToken(address hostRecipient, address token, uint256 amount) public {
if (amount == 0) return;
IERC20(token).transferFrom(msg.sender, address(this), amount);
ERC20Burnable(token).burn(amount);
emit ExitToken(hostRecipient, token, amount);
}
}
3 changes: 2 additions & 1 deletion test/Helpers.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ pragma solidity ^0.8.24;
import {Test, console2} from "forge-std/Test.sol";
import {Zenith} from "../src/Zenith.sol";
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract TestERC20 is ERC20 {
contract TestERC20 is ERC20Burnable {
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {}

function mint(address recipient, uint256 amount) external {
Expand Down
52 changes: 51 additions & 1 deletion test/Passage.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
pragma solidity ^0.8.24;

import {Test, console2} from "forge-std/Test.sol";
import {Passage} from "../src/Passage.sol";
import {Passage, RollupPassage} from "../src/Passage.sol";
import {TestERC20} from "./Helpers.t.sol";
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract PassageTest is Test {
Passage public target;
Expand Down Expand Up @@ -189,3 +190,52 @@ contract PassageTest is Test {
target.withdraw(token, recipient, amount);
}
}

contract RollupPassageTest is Test {
RollupPassage public target;
address token;
address recipient = address(0x123);
uint256 amount = 200;

event Exit(address indexed hostRecipient, uint256 amount);

event ExitToken(address indexed hostRecipient, address indexed token, uint256 amount);

function setUp() public {
// deploy target
target = new RollupPassage();

// deploy token
token = address(new TestERC20("hi", "HI"));
TestERC20(token).mint(address(this), amount * 10000);
TestERC20(token).approve(address(target), amount * 10000);
}

function test_receive() public {
vm.expectEmit();
emit Exit(address(this), amount);
address(target).call{value: amount}("");
}

function test_fallback() public {
vm.expectEmit();
emit Exit(address(this), amount);
address(target).call{value: amount}("0xabcd");
}

function test_exit() public {
vm.expectEmit();
emit Exit(recipient, amount);
target.exit{value: amount}(recipient);
}

function test_exitToken() public {
vm.expectEmit();
emit ExitToken(recipient, token, amount);
vm.expectCall(
token, abi.encodeWithSelector(ERC20.transferFrom.selector, address(this), address(target), amount)
);
vm.expectCall(token, abi.encodeWithSelector(ERC20Burnable.burn.selector, amount));
target.exitToken(recipient, token, amount);
}
}