Skip to content

Commit 5d70919

Browse files
authored
refactor: split Passage enter/exit from Orders (#41)
* refactor: split Passage enter/exit from Orders * reorder * comment * remove ERC20 enter/exits for now * add enter with no chainid * remove more ERC20 enter things * rename Order contract * rm exit while spec in progress
1 parent 963d5a7 commit 5d70919

File tree

4 files changed

+142
-130
lines changed

4 files changed

+142
-130
lines changed

.gas-snapshot

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
ZenithTest:test_badSequence() (gas: 60188)
2-
ZenithTest:test_badSignature() (gas: 66804)
3-
ZenithTest:test_blockExpired() (gas: 55419)
4-
ZenithTest:test_notSequencer() (gas: 58524)
5-
ZenithTest:test_onePerBlock() (gas: 104196)
6-
ZenithTest:test_submitBlock() (gas: 88425)
1+
ZenithTest:test_badSequence() (gas: 60199)
2+
ZenithTest:test_badSignature() (gas: 66867)
3+
ZenithTest:test_blockExpired() (gas: 55430)
4+
ZenithTest:test_notSequencer() (gas: 58572)
5+
ZenithTest:test_onePerBlock() (gas: 104311)
6+
ZenithTest:test_submitBlock() (gas: 88457)

script/Zenith.s.sol

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,25 @@ pragma solidity ^0.8.24;
33

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

78
contract ZenithScript is Script {
89
// deploy:
910
// forge script ZenithScript --sig "deploy(uint256,address,address)" --rpc-url $RPC_URL --etherscan-api-key $ETHERSCAN_API_KEY --private-key $PRIVATE_KEY --broadcast --verify $ROLLUP_CHAIN_ID $WITHDRAWAL_ADMIN_ADDRESS $SEQUENCER_ADMIN_ADDRESS
1011
function deploy(uint256 defaultRollupChainId, address withdrawalAdmin, address sequencerAdmin)
1112
public
12-
returns (Zenith z)
13+
returns (Zenith z, HostOrders m)
1314
{
1415
vm.startBroadcast();
1516
z = new Zenith(defaultRollupChainId, withdrawalAdmin, sequencerAdmin);
17+
m = new HostOrders();
18+
}
19+
20+
// deploy:
21+
// forge script ZenithScript --sig "deployL2()" --rpc-url $L2_RPC_URL --private-key $PRIVATE_KEY --broadcast $ZENITH_ADDRESS
22+
function deployL2(address zenith) public returns (RollupOrders m) {
23+
vm.startBroadcast();
24+
m = new RollupOrders();
1625
}
1726

1827
// NOTE: script must be run using SequencerAdmin key

src/Orders.sol

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.24;
3+
4+
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
5+
6+
/// @notice Contract capable of processing fulfillment of intent-based Orders.
7+
abstract contract OrderDestination {
8+
/// @notice Emitted when an swap order is fulfilled by the Builder.
9+
/// @param originChainId - The chainId on which the swap order was submitted.
10+
/// @param token - The address of the token transferred to the recipient. address(0) corresponds to native Ether.
11+
/// @param recipient - The recipient of the token.
12+
/// @param amount - The amount of the token transferred to the recipient.
13+
event SwapFulfilled(
14+
uint256 indexed originChainId, address indexed token, address indexed recipient, uint256 amount
15+
);
16+
17+
/// @notice Fulfill a rollup Swap order.
18+
/// The user calls `swap` on a rollup; the Builder calls `fulfillSwap` on the target chain.
19+
/// @custom:emits SwapFulfilled
20+
/// @param originChainId - The chainId of the rollup on which `swap` was called.
21+
/// @param token - The address of the token to be transferred to the recipient.
22+
/// address(0) corresponds to native Ether.
23+
/// @param recipient - The recipient of the token.
24+
/// @param amount - The amount of the token to be transferred to the recipient.
25+
function fulfillSwap(uint256 originChainId, address token, address recipient, uint256 amount) external payable {
26+
if (token == address(0)) {
27+
require(amount == msg.value);
28+
payable(recipient).transfer(msg.value);
29+
} else {
30+
IERC20(token).transferFrom(msg.sender, recipient, amount);
31+
}
32+
emit SwapFulfilled(originChainId, token, recipient, amount);
33+
}
34+
}
35+
36+
/// @notice Contract capable of registering initiation of intent-based Orders.
37+
abstract contract OrderOrigin {
38+
/// @notice Thrown when an swap transaction is submitted with a deadline that has passed.
39+
error OrderExpired();
40+
41+
/// @notice Emitted when an swap order is successfully processed, indicating it was also fulfilled on the target chain.
42+
/// @dev See `swap` for parameter docs.
43+
event Swap(
44+
uint256 indexed targetChainId,
45+
address indexed tokenIn,
46+
address indexed tokenOut,
47+
address recipient,
48+
uint256 deadline,
49+
uint256 amountIn,
50+
uint256 amountOut
51+
);
52+
53+
/// @notice Emitted when tokens or native Ether is swept from the contract.
54+
/// @dev Intended to improve visibility for Builders to ensure Sweep isn't called unexpectedly.
55+
/// Intentionally does not bother to emit which token(s) were swept, nor their amounts.
56+
event Sweep(address indexed token, address indexed recipient, uint256 amount);
57+
58+
/// @notice Request to swap ERC20s.
59+
/// @dev tokenIn is provided on the rollup; in exchange,
60+
/// tokenOut is expected to be received on targetChainId.
61+
/// @dev targetChainId may be the current chainId, the Host chainId, or..
62+
/// @dev Fees paid to the Builders for fulfilling the swap orders
63+
/// can be included within the "exchange rate" between tokenIn and tokenOut.
64+
/// @dev The Builder claims the tokenIn from the contract by submitting a transaction to `sweep` the tokens within the same block.
65+
/// @dev The Rollup STF MUST NOT apply `swap` transactions to the rollup state
66+
/// UNLESS a sufficient SwapFulfilled event is emitted on the target chain within the same block.
67+
/// @param targetChainId - The chain on which tokens should be output.
68+
/// @param tokenIn - The address of the token the user supplies as the input on the rollup for the trade.
69+
/// @param tokenOut - The address of the token the user expects to receive on the target chain.
70+
/// @param recipient - The address of the recipient of tokenOut on the target chain.
71+
/// @param deadline - The deadline by which the swap order must be fulfilled.
72+
/// @param amountIn - The amount of tokenIn the user supplies as the input on the rollup for the trade.
73+
/// @param amountOut - The minimum amount of tokenOut the user expects to receive on the target chain.
74+
/// @custom:reverts Expired if the deadline has passed.
75+
/// @custom:emits Swap if the swap transaction succeeds.
76+
function swap(
77+
uint256 targetChainId,
78+
address tokenIn,
79+
address tokenOut,
80+
address recipient,
81+
uint256 deadline,
82+
uint256 amountIn,
83+
uint256 amountOut
84+
) external payable {
85+
// check that the deadline hasn't passed
86+
if (block.timestamp >= deadline) revert OrderExpired();
87+
88+
if (tokenIn == address(0)) {
89+
require(amountIn == msg.value);
90+
} else {
91+
IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
92+
}
93+
94+
// emit the swap event
95+
emit Swap(targetChainId, tokenIn, tokenOut, recipient, deadline, amountIn, amountOut);
96+
}
97+
98+
/// @notice Transfer the entire balance of ERC20 tokens to the recipient.
99+
/// @dev Called by the Builder within the same block as users' `swap` transactions
100+
/// to claim the amounts of `tokenIn`.
101+
/// @dev Builder MUST ensure that no other account calls `sweep` before them.
102+
/// @param token - The token to transfer.
103+
/// @param recipient - The address to receive the tokens.
104+
function sweep(address token, address recipient) public {
105+
uint256 balance;
106+
if (token == address(0)) {
107+
balance = address(this).balance;
108+
payable(recipient).transfer(balance);
109+
} else {
110+
balance = IERC20(token).balanceOf(address(this));
111+
IERC20(token).transfer(recipient, balance);
112+
}
113+
emit Sweep(token, recipient, balance);
114+
}
115+
}
116+
117+
contract HostOrders is OrderDestination {}
118+
119+
contract RollupOrders is OrderOrigin, OrderDestination {}

src/Passage.sol

Lines changed: 7 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,9 @@ pragma solidity ^0.8.24;
33

44
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
55

6-
contract BasePassage {
7-
/// @notice Emitted when an swap order is fulfilled by the Builder.
8-
/// @param originChainId - The chainId on which the swap order was submitted.
9-
/// @param token - The address of the token transferred to the recipient. address(0) corresponds to native Ether.
10-
/// @param recipient - The recipient of the token.
11-
/// @param amount - The amount of the token transferred to the recipient.
12-
event SwapFulfilled(
13-
uint256 indexed originChainId, address indexed token, address indexed recipient, uint256 amount
14-
);
15-
16-
/// @notice Fulfill a rollup Swap order.
17-
/// The user calls `swap` on a rollup; the Builder calls `fulfillSwap` on the target chain.
18-
/// @custom:emits SwapFulfilled
19-
/// @param originChainId - The chainId of the rollup on which `swap` was called.
20-
/// @param token - The address of the token to be transferred to the recipient.
21-
/// address(0) corresponds to native Ether.
22-
/// @param recipient - The recipient of the token.
23-
/// @param amount - The amount of the token to be transferred to the recipient.
24-
function fulfillSwap(uint256 originChainId, address token, address recipient, uint256 amount) external payable {
25-
if (token == address(0)) {
26-
require(amount == msg.value);
27-
payable(recipient).transfer(msg.value);
28-
} else {
29-
IERC20(token).transferFrom(msg.sender, recipient, amount);
30-
}
31-
emit SwapFulfilled(originChainId, token, recipient, amount);
32-
}
33-
}
34-
356
/// @notice A contract deployed to Host chain that allows tokens to enter the rollup,
367
/// and enables Builders to fulfill requests to exchange tokens on the Rollup for tokens on the Host.
37-
contract Passage is BasePassage {
8+
contract Passage {
389
/// @notice The chainId of rollup that Ether will be sent to by default when entering the rollup via fallback() or receive().
3910
uint256 public immutable defaultRollupChainId;
4011

@@ -71,24 +42,18 @@ contract Passage is BasePassage {
7142
}
7243

7344
/// @notice Allows native Ether to enter the rollup.
74-
/// @dev Permanently burns the entire msg.value by locking it in this contract.
75-
/// @param rollupChainId - The rollup chain to enter.
7645
/// @param rollupRecipient - The recipient of the Ether on the rollup.
7746
/// @custom:emits Enter indicating the amount of Ether to mint on the rollup & its recipient.
78-
function enter(uint256 rollupChainId, address rollupRecipient) public payable {
79-
emit Enter(rollupChainId, address(0), rollupRecipient, msg.value);
47+
function enter(address rollupRecipient) public payable {
48+
enter(defaultRollupChainId, rollupRecipient);
8049
}
8150

82-
/// @notice Allows ERC20s to enter the rollup.
83-
/// @dev Permanently burns the token amount by locking it in this contract.
51+
/// @notice Allows native Ether to enter the rollup.
8452
/// @param rollupChainId - The rollup chain to enter.
8553
/// @param rollupRecipient - The recipient of the Ether on the rollup.
86-
/// @param token - The address of the ERC20 token on the Host.
87-
/// @param amount - The amount of the ERC20 token to transfer to the rollup.
88-
/// @custom:emits Enter indicating the amount of tokens to mint on the rollup & its recipient.
89-
function enter(uint256 rollupChainId, address token, address rollupRecipient, uint256 amount) external payable {
90-
IERC20(token).transferFrom(msg.sender, address(this), amount);
91-
emit Enter(rollupChainId, token, rollupRecipient, amount);
54+
/// @custom:emits Enter indicating the amount of Ether to mint on the rollup & its recipient.
55+
function enter(uint256 rollupChainId, address rollupRecipient) public payable {
56+
emit Enter(rollupChainId, address(0), rollupRecipient, msg.value);
9257
}
9358

9459
/// @notice Allows the admin to withdraw ETH or ERC20 tokens from the contract.
@@ -103,84 +68,3 @@ contract Passage is BasePassage {
10368
emit Withdrawal(token, recipient, amount);
10469
}
10570
}
106-
107-
/// @notice A contract deployed to the Rollup that allows users to atomically exchange tokens on the Rollup for tokens on the Host.
108-
contract RollupPassage is BasePassage {
109-
/// @notice Thrown when an swap transaction is submitted with a deadline that has passed.
110-
error OrderExpired();
111-
112-
/// @notice Emitted when an swap order is successfully processed, indicating it was also fulfilled on the target chain.
113-
/// @dev See `swap` for parameter docs.
114-
event Swap(
115-
uint256 indexed targetChainId,
116-
address indexed tokenIn,
117-
address indexed tokenOut,
118-
address recipient,
119-
uint256 deadline,
120-
uint256 amountIn,
121-
uint256 amountOut
122-
);
123-
124-
/// @notice Emitted when tokens or native Ether is swept from the contract.
125-
/// @dev Intended to improve visibility for Builders to ensure Sweep isn't called unexpectedly.
126-
/// Intentionally does not bother to emit which token(s) were swept, nor their amounts.
127-
event Sweep(address indexed token, address indexed recipient, uint256 amount);
128-
129-
/// @notice Request to swap ERC20s.
130-
/// @dev tokenIn is provided on the rollup; in exchange,
131-
/// tokenOut is expected to be received on targetChainId.
132-
/// @dev targetChainId may be the current chainId, the Host chainId, or..
133-
/// @dev Fees paid to the Builders for fulfilling the swap orders
134-
/// can be included within the "exchange rate" between tokenIn and tokenOut.
135-
/// @dev The Builder claims the tokenIn from the contract by submitting a transaction to `sweep` the tokens within the same block.
136-
/// @dev The Rollup STF MUST NOT apply `swap` transactions to the rollup state
137-
/// UNLESS a sufficient SwapFulfilled event is emitted on the target chain within the same block.
138-
/// @param targetChainId - The chain on which tokens should be output.
139-
/// @param tokenIn - The address of the token the user supplies as the input on the rollup for the trade.
140-
/// @param tokenOut - The address of the token the user expects to receive on the target chain.
141-
/// @param recipient - The address of the recipient of tokenOut on the target chain.
142-
/// @param deadline - The deadline by which the swap order must be fulfilled.
143-
/// @param amountIn - The amount of tokenIn the user supplies as the input on the rollup for the trade.
144-
/// @param amountOut - The minimum amount of tokenOut the user expects to receive on the target chain.
145-
/// @custom:reverts Expired if the deadline has passed.
146-
/// @custom:emits Swap if the swap transaction succeeds.
147-
function swap(
148-
uint256 targetChainId,
149-
address tokenIn,
150-
address tokenOut,
151-
address recipient,
152-
uint256 deadline,
153-
uint256 amountIn,
154-
uint256 amountOut
155-
) external payable {
156-
// check that the deadline hasn't passed
157-
if (block.timestamp >= deadline) revert OrderExpired();
158-
159-
if (tokenIn == address(0)) {
160-
require(amountIn == msg.value);
161-
} else {
162-
IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
163-
}
164-
165-
// emit the swap event
166-
emit Swap(targetChainId, tokenIn, tokenOut, recipient, deadline, amountIn, amountOut);
167-
}
168-
169-
/// @notice Transfer the entire balance of ERC20 tokens to the recipient.
170-
/// @dev Called by the Builder within the same block as users' `swap` transactions
171-
/// to claim the amounts of `tokenIn`.
172-
/// @dev Builder MUST ensure that no other account calls `sweep` before them.
173-
/// @param token - The token to transfer.
174-
/// @param recipient - The address to receive the tokens.
175-
function sweep(address token, address recipient) public {
176-
uint256 balance;
177-
if (token == address(0)) {
178-
balance = address(this).balance;
179-
payable(recipient).transfer(balance);
180-
} else {
181-
balance = IERC20(token).balanceOf(address(this));
182-
IERC20(token).transfer(recipient, balance);
183-
}
184-
emit Sweep(token, recipient, balance);
185-
}
186-
}

0 commit comments

Comments
 (0)