2
2
pragma solidity ^ 0.8.24 ;
3
3
4
4
import {IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol " ;
5
-
6
- /// @notice Tokens sent by the swapper as inputs to the order
7
- /// @dev From ERC-7683
8
- struct Input {
9
- /// @dev The address of the ERC20 token on the origin chain
10
- address token;
11
- /// @dev The amount of the token to be sent
12
- uint256 amount;
13
- }
14
-
15
- /// @notice Tokens that must be receive for a valid order fulfillment
16
- /// @dev From ERC-7683
17
- struct Output {
18
- /// @dev The address of the ERC20 token on the destination chain
19
- /// @dev address(0) used as a sentinel for the native token
20
- address token;
21
- /// @dev The amount of the token to be sent
22
- uint256 amount;
23
- /// @dev The address to receive the output tokens
24
- address recipient;
25
- /// @dev When emitted on the origin chain, the destination chain for the Output.
26
- /// When emitted on the destination chain, the origin chain for the Order containing the Output.
27
- uint32 chainId;
28
- }
5
+ import {Permit2Batch, UsesPermit2} from "./UsesPermit2.sol " ;
6
+ import {IOrders} from "./IOrders.sol " ;
29
7
30
8
/// @notice Contract capable of processing fulfillment of intent-based Orders.
31
- abstract contract OrderDestination {
9
+ abstract contract OrderDestination is IOrders , UsesPermit2 {
32
10
/// @notice Emitted when Order Outputs are sent to their recipients.
33
11
/// @dev NOTE that here, Output.chainId denotes the *origin* chainId.
34
12
event Filled (Output[] outputs );
35
13
36
- /// @notice Send the Output(s) of any number of Orders.
37
- /// The user calls `initiate` on a rollup; the Builder calls `fill` on the target chain aggregating Outputs.
38
- /// Builder may aggregate multiple Outputs with the same (`chainId`, `recipient`, `token`) into a single Output with the summed `amount`.
14
+ /// @notice Fill any number of Order(s), by transferring their Output(s).
15
+ /// @dev Filler may aggregate multiple Outputs with the same (`chainId`, `recipient`, `token`) into a single Output with the summed `amount`.
39
16
/// @dev NOTE that here, Output.chainId denotes the *origin* chainId.
40
17
/// @param outputs - The Outputs to be transferred.
41
18
/// @custom:emits Filled
42
19
function fill (Output[] memory outputs ) external payable {
43
20
// transfer outputs
21
+ _transferOutputs (outputs);
22
+
23
+ // emit
24
+ emit Filled (outputs);
25
+ }
26
+
27
+ /// @notice Transfer the Order Outputs to their recipients.
28
+ function _transferOutputs (Output[] memory outputs ) internal {
44
29
uint256 value = msg .value ;
45
30
for (uint256 i; i < outputs.length ; i++ ) {
46
31
if (outputs[i].token == address (0 )) {
@@ -51,19 +36,32 @@ abstract contract OrderDestination {
51
36
IERC20 (outputs[i].token).transferFrom (msg .sender , outputs[i].recipient, outputs[i].amount);
52
37
}
53
38
}
39
+ }
40
+
41
+ /// @notice Fill any number of Order(s), by transferring their Output(s) via permit2 signed batch transfer.
42
+ /// @dev Can only provide ERC20 tokens as Outputs.
43
+ /// @dev Filler may aggregate multiple Outputs with the same (`chainId`, `recipient`, `token`) into a single Output with the summed `amount`.
44
+ /// @dev the permit2 signer is the Filler providing the Outputs.
45
+ /// @dev the permit2 `permitted` tokens MUST match provided Outputs.
46
+ /// @dev Filler MUST submit `fill` and `intitiate` within an atomic bundle.
47
+ /// @dev NOTE that here, Output.chainId denotes the *origin* chainId.
48
+ /// @param outputs - The Outputs to be transferred. signed over via permit2 witness.
49
+ /// @param permit2 - the permit2 details, signer, and signature.
50
+ /// @custom:emits Filled
51
+ function fillPermit2 (Output[] memory outputs , Permit2Batch calldata permit2 ) external {
52
+ // transfer all tokens to the Output recipients via permit2 (includes check on nonce & deadline)
53
+ _permitWitnessTransferFrom (outputs, _fillTransferDetails (outputs, permit2.permit.permitted), permit2);
54
+
54
55
// emit
55
56
emit Filled (outputs);
56
57
}
57
58
}
58
59
59
60
/// @notice Contract capable of registering initiation of intent-based Orders.
60
- abstract contract OrderOrigin {
61
+ abstract contract OrderOrigin is IOrders , UsesPermit2 {
61
62
/// @notice Thrown when an Order is submitted with a deadline that has passed.
62
63
error OrderExpired ();
63
64
64
- /// @notice Thrown when trying to call `sweep` if not the Builder of the block.
65
- error OnlyBuilder ();
66
-
67
65
/// @notice Emitted when an Order is submitted for fulfillment.
68
66
/// @dev NOTE that here, Output.chainId denotes the *destination* chainId.
69
67
event Order (uint256 deadline , Input[] inputs , Output[] outputs );
@@ -73,14 +71,15 @@ abstract contract OrderOrigin {
73
71
/// Intentionally does not bother to emit which token(s) were swept, nor their amounts.
74
72
event Sweep (address indexed recipient , address indexed token , uint256 amount );
75
73
76
- /// @notice Request to swap ERC20s.
74
+ /// @notice Initiate an Order.
75
+ /// @dev Filler MUST submit `fill` and `intitiate` + `sweep` within an atomic bundle.
76
+ /// @dev NOTE that here, Output.chainId denotes the *target* chainId.
77
77
/// @dev inputs are provided on the rollup; in exchange,
78
78
/// outputs are expected to be received on the target chain(s).
79
- /// @dev Fees paid to the Builders for fulfilling the Orders
80
- /// can be included within the "exchange rate" between inputs and outputs.
81
- /// @dev The Builder claims the inputs from the contract by submitting `sweep` transactions within the same block.
82
79
/// @dev The Rollup STF MUST NOT apply `initiate` transactions to the rollup state
83
80
/// UNLESS the outputs are delivered on the target chains within the same block.
81
+ /// @dev Fees paid to the Builders for fulfilling the Orders
82
+ /// can be included within the "exchange rate" between inputs and outputs.
84
83
/// @param deadline - The deadline at or before which the Order must be fulfilled.
85
84
/// @param inputs - The token amounts offered by the swapper in exchange for the outputs.
86
85
/// @param outputs - The token amounts that must be received on their target chain(s) in order for the Order to be executed.
@@ -97,7 +96,7 @@ abstract contract OrderOrigin {
97
96
emit Order (deadline, inputs, outputs);
98
97
}
99
98
100
- /// @notice Transfer the Order inputs to this contract, where they can be collected by the Order filler.
99
+ /// @notice Transfer the Order inputs to this contract, where they can be collected by the Order filler via `sweep` .
101
100
function _transferInputs (Input[] memory inputs ) internal {
102
101
uint256 value = msg .value ;
103
102
for (uint256 i; i < inputs.length ; i++ ) {
@@ -110,6 +109,22 @@ abstract contract OrderOrigin {
110
109
}
111
110
}
112
111
112
+ /// @notice Initiate an Order, transferring Input tokens to the Filler via permit2 signed batch transfer.
113
+ /// @dev Can only provide ERC20 tokens as Inputs.
114
+ /// @dev the permit2 signer is the swapper providing the Input tokens in exchange for the Outputs.
115
+ /// @dev Filler MUST submit `fill` and `intitiate` within an atomic bundle.
116
+ /// @dev NOTE that here, Output.chainId denotes the *target* chainId.
117
+ /// @param tokenRecipient - the recipient of the Input tokens, provided by msg.sender (un-verified by permit2).
118
+ /// @param outputs - the Outputs required in exchange for the Input tokens. signed over via permit2 witness.
119
+ /// @param permit2 - the permit2 details, signer, and signature.
120
+ function initiatePermit2 (address tokenRecipient , Output[] memory outputs , Permit2Batch calldata permit2 ) external {
121
+ // transfer all tokens to the tokenRecipient via permit2 (includes check on nonce & deadline)
122
+ _permitWitnessTransferFrom (outputs, _initiateTransferDetails (tokenRecipient, permit2.permit.permitted), permit2);
123
+
124
+ // emit
125
+ emit Order (permit2.permit.deadline, _inputs (permit2.permit.permitted), outputs);
126
+ }
127
+
113
128
/// @notice Transfer the entire balance of ERC20 tokens to the recipient.
114
129
/// @dev Called by the Builder within the same block as users' `initiate` transactions
115
130
/// to claim the `inputs`.
@@ -119,7 +134,6 @@ abstract contract OrderOrigin {
119
134
/// @custom:emits Sweep
120
135
/// @custom:reverts OnlyBuilder if called by non-block builder
121
136
function sweep (address recipient , address token ) public {
122
- if (msg .sender != block .coinbase ) revert OnlyBuilder ();
123
137
// send ETH or tokens
124
138
uint256 balance;
125
139
if (token == address (0 )) {
@@ -133,6 +147,10 @@ abstract contract OrderOrigin {
133
147
}
134
148
}
135
149
136
- contract HostOrders is OrderDestination {}
150
+ contract HostOrders is OrderDestination {
151
+ constructor (address _permit2 ) UsesPermit2 (_permit2) {}
152
+ }
137
153
138
- contract RollupOrders is OrderOrigin , OrderDestination {}
154
+ contract RollupOrders is OrderOrigin , OrderDestination {
155
+ constructor (address _permit2 ) UsesPermit2 (_permit2) {}
156
+ }
0 commit comments