Skip to content

Commit a24ddde

Browse files
authored
feat: RollupPassage contract (#60)
* feat: RollupPassage contract * test: RollupPassage * add RollupPassage to deploy script
1 parent 81e9690 commit a24ddde

File tree

5 files changed

+108
-9
lines changed

5 files changed

+108
-9
lines changed

.gas-snapshot

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ OrdersTest:test_fill_underflowETH() (gas: 115281)
66
OrdersTest:test_initiate_ERC20() (gas: 81435)
77
OrdersTest:test_initiate_ETH() (gas: 44949)
88
OrdersTest:test_initiate_both() (gas: 118677)
9-
OrdersTest:test_initiate_multiERC20() (gas: 688417)
9+
OrdersTest:test_initiate_multiERC20() (gas: 722408)
1010
OrdersTest:test_initiate_multiETH() (gas: 75304)
1111
OrdersTest:test_onlyBuilder() (gas: 12815)
1212
OrdersTest:test_orderExpired() (gas: 27956)
13-
OrdersTest:test_sweepERC20() (gas: 60402)
13+
OrdersTest:test_sweepERC20() (gas: 60446)
1414
OrdersTest:test_sweepETH() (gas: 81940)
1515
OrdersTest:test_underflowETH() (gas: 63528)
1616
PassageTest:test_configureEnter() (gas: 82311)
@@ -26,7 +26,11 @@ PassageTest:test_receive() (gas: 21384)
2626
PassageTest:test_setUp() (gas: 16968)
2727
PassageTest:test_transact() (gas: 58562)
2828
PassageTest:test_transact_defaultChain() (gas: 57475)
29-
PassageTest:test_withdraw() (gas: 59033)
29+
PassageTest:test_withdraw() (gas: 59166)
30+
RollupPassageTest:test_exit() (gas: 22347)
31+
RollupPassageTest:test_exitToken() (gas: 50183)
32+
RollupPassageTest:test_fallback() (gas: 19883)
33+
RollupPassageTest:test_receive() (gas: 19844)
3034
ZenithTest:test_addSequencer() (gas: 88121)
3135
ZenithTest:test_badSignature() (gas: 37241)
3236
ZenithTest:test_incorrectHostBlock() (gas: 35086)

script/Zenith.s.sol

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pragma solidity ^0.8.24;
33

44
import {Script} from "forge-std/Script.sol";
55
import {Zenith} from "../src/Zenith.sol";
6-
import {Passage} from "../src/Passage.sol";
6+
import {Passage, RollupPassage} from "../src/Passage.sol";
77
import {HostOrders, RollupOrders} from "../src/Orders.sol";
88

99
contract ZenithScript is Script {
@@ -23,8 +23,9 @@ contract ZenithScript is Script {
2323

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

src/Passage.sol

+45-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
pragma solidity ^0.8.24;
33

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

6-
/// @notice A contract deployed to Host chain that allows tokens to enter the rollup,
7-
/// and enables Builders to fulfill requests to exchange tokens on the Rollup for tokens on the Host.
7+
/// @notice A contract deployed to Host chain that allows tokens to enter the rollup.
88
contract Passage {
99
/// @notice The chainId of rollup that Ether will be sent to by default when entering the rollup via fallback() or receive().
1010
uint256 public immutable defaultRollupChainId;
@@ -178,3 +178,46 @@ contract Passage {
178178
emit EnterConfigured(token, _canEnter);
179179
}
180180
}
181+
182+
/// @notice Enables tokens to Exit the rollup.
183+
contract RollupPassage {
184+
/// @notice Emitted when native Ether exits the rollup.
185+
/// @param hostRecipient - The *requested* recipient of tokens on the host chain.
186+
/// @param amount - The amount of Ether exiting the rollup.
187+
event Exit(address indexed hostRecipient, uint256 amount);
188+
189+
/// @notice Emitted when ERC20 tokens exit the rollup.
190+
/// @param hostRecipient - The *requested* recipient of tokens on the host chain.
191+
/// @param token - The token exiting the rollup.
192+
/// @param amount - The amount of ERC20s exiting the rollup.
193+
event ExitToken(address indexed hostRecipient, address indexed token, uint256 amount);
194+
195+
/// @notice Allows native Ether to exit the rollup by being sent directly to the contract.
196+
fallback() external payable {
197+
exit(msg.sender);
198+
}
199+
200+
/// @notice Allows native Ether to exit the rollup by being sent directly to the contract.
201+
receive() external payable {
202+
exit(msg.sender);
203+
}
204+
205+
/// @notice Allows native Ether to exit the rollup.
206+
/// @param hostRecipient - The *requested* recipient of tokens on the host chain.
207+
/// @custom:emits Exit indicating the amount of Ether that was locked on the rollup & the requested host recipient.
208+
function exit(address hostRecipient) public payable {
209+
if (msg.value == 0) return;
210+
emit Exit(hostRecipient, msg.value);
211+
}
212+
213+
/// @notice Allows ERC20 tokens to exit the rollup.
214+
/// @param hostRecipient - The *requested* recipient of tokens on the host chain.
215+
/// @param token - The rollup address of the token exiting the rollup.
216+
/// @param amount - The amount of tokens exiting the rollup.
217+
function exitToken(address hostRecipient, address token, uint256 amount) public {
218+
if (amount == 0) return;
219+
IERC20(token).transferFrom(msg.sender, address(this), amount);
220+
ERC20Burnable(token).burn(amount);
221+
emit ExitToken(hostRecipient, token, amount);
222+
}
223+
}

test/Helpers.t.sol

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ pragma solidity ^0.8.24;
44
import {Test, console2} from "forge-std/Test.sol";
55
import {Zenith} from "../src/Zenith.sol";
66
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
7+
import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";
78

8-
contract TestERC20 is ERC20 {
9+
contract TestERC20 is ERC20Burnable {
910
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {}
1011

1112
function mint(address recipient, uint256 amount) external {

test/Passage.t.sol

+51-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
pragma solidity ^0.8.24;
33

44
import {Test, console2} from "forge-std/Test.sol";
5-
import {Passage} from "../src/Passage.sol";
5+
import {Passage, RollupPassage} from "../src/Passage.sol";
66
import {TestERC20} from "./Helpers.t.sol";
77
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
8+
import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";
89

910
contract PassageTest is Test {
1011
Passage public target;
@@ -189,3 +190,52 @@ contract PassageTest is Test {
189190
target.withdraw(token, recipient, amount);
190191
}
191192
}
193+
194+
contract RollupPassageTest is Test {
195+
RollupPassage public target;
196+
address token;
197+
address recipient = address(0x123);
198+
uint256 amount = 200;
199+
200+
event Exit(address indexed hostRecipient, uint256 amount);
201+
202+
event ExitToken(address indexed hostRecipient, address indexed token, uint256 amount);
203+
204+
function setUp() public {
205+
// deploy target
206+
target = new RollupPassage();
207+
208+
// deploy token
209+
token = address(new TestERC20("hi", "HI"));
210+
TestERC20(token).mint(address(this), amount * 10000);
211+
TestERC20(token).approve(address(target), amount * 10000);
212+
}
213+
214+
function test_receive() public {
215+
vm.expectEmit();
216+
emit Exit(address(this), amount);
217+
address(target).call{value: amount}("");
218+
}
219+
220+
function test_fallback() public {
221+
vm.expectEmit();
222+
emit Exit(address(this), amount);
223+
address(target).call{value: amount}("0xabcd");
224+
}
225+
226+
function test_exit() public {
227+
vm.expectEmit();
228+
emit Exit(recipient, amount);
229+
target.exit{value: amount}(recipient);
230+
}
231+
232+
function test_exitToken() public {
233+
vm.expectEmit();
234+
emit ExitToken(recipient, token, amount);
235+
vm.expectCall(
236+
token, abi.encodeWithSelector(ERC20.transferFrom.selector, address(this), address(target), amount)
237+
);
238+
vm.expectCall(token, abi.encodeWithSelector(ERC20Burnable.burn.selector, amount));
239+
target.exitToken(recipient, token, amount);
240+
}
241+
}

0 commit comments

Comments
 (0)