Skip to content
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

demo: add permit flow #62

Closed
wants to merge 1 commit into from
Closed
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
44 changes: 22 additions & 22 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
OrdersTest:test_fill_ERC20() (gas: 70364)
OrdersTest:test_fill_ETH() (gas: 68414)
OrdersTest:test_fill_both() (gas: 166580)
OrdersTest:test_fill_multiETH() (gas: 131926)
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_multiETH() (gas: 75304)
OrdersTest:test_onlyBuilder() (gas: 12815)
OrdersTest:test_orderExpired() (gas: 27956)
OrdersTest:test_sweepERC20() (gas: 60402)
OrdersTest:test_sweepETH() (gas: 81940)
OrdersTest:test_underflowETH() (gas: 63528)
PassageTest:test_configureEnter() (gas: 82311)
OrdersTest:test_fill_ERC20() (gas: 70408)
OrdersTest:test_fill_ETH() (gas: 68458)
OrdersTest:test_fill_both() (gas: 166624)
OrdersTest:test_fill_multiETH() (gas: 131970)
OrdersTest:test_fill_underflowETH() (gas: 115325)
OrdersTest:test_initiate_ERC20() (gas: 81505)
OrdersTest:test_initiate_ETH() (gas: 45019)
OrdersTest:test_initiate_both() (gas: 118738)
OrdersTest:test_initiate_multiERC20() (gas: 688478)
OrdersTest:test_initiate_multiETH() (gas: 75365)
OrdersTest:test_onlyBuilder() (gas: 12859)
OrdersTest:test_orderExpired() (gas: 28026)
OrdersTest:test_sweepERC20() (gas: 60446)
OrdersTest:test_sweepETH() (gas: 82054)
OrdersTest:test_underflowETH() (gas: 63589)
PassageTest:test_configureEnter() (gas: 82357)
PassageTest:test_disallowedEnter() (gas: 17916)
PassageTest:test_enter() (gas: 25563)
PassageTest:test_enter() (gas: 25541)
PassageTest:test_enterToken() (gas: 64332)
PassageTest:test_enterToken_defaultChain() (gas: 62915)
PassageTest:test_enterTransact() (gas: 60890)
PassageTest:test_enter_defaultChain() (gas: 24033)
PassageTest:test_enterTransact() (gas: 60936)
PassageTest:test_enter_defaultChain() (gas: 24011)
PassageTest:test_fallback() (gas: 21534)
PassageTest:test_onlyTokenAdmin() (gas: 16926)
PassageTest:test_onlyTokenAdmin() (gas: 16927)
PassageTest:test_receive() (gas: 21384)
PassageTest:test_setUp() (gas: 16968)
PassageTest:test_setUp() (gas: 16991)
PassageTest:test_transact() (gas: 58562)
PassageTest:test_transact_defaultChain() (gas: 57475)
PassageTest:test_withdraw() (gas: 59033)
PassageTest:test_withdraw() (gas: 59011)
ZenithTest:test_addSequencer() (gas: 88121)
ZenithTest:test_badSignature() (gas: 37241)
ZenithTest:test_incorrectHostBlock() (gas: 35086)
Expand Down
26 changes: 22 additions & 4 deletions src/Orders.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.24;

import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {Permit, PermitLib} from "./Permit.sol";

/// @notice Tokens sent by the swapper as inputs to the order
/// @dev From ERC-7683
Expand All @@ -28,7 +29,7 @@ struct Output {
}

/// @notice Contract capable of processing fulfillment of intent-based Orders.
abstract contract OrderDestination {
abstract contract OrderDestination is PermitLib {
/// @notice Emitted when Order Outputs are sent to their recipients.
/// @dev NOTE that here, Output.chainId denotes the *origin* chainId.
event Filled(Output[] outputs);
Expand All @@ -39,7 +40,7 @@ abstract contract OrderDestination {
/// @dev NOTE that here, Output.chainId denotes the *origin* chainId.
/// @param outputs - The Outputs to be transferred.
/// @custom:emits Filled
function fill(Output[] memory outputs) external payable {
function fill(Output[] memory outputs) public payable {
// transfer outputs
uint256 value = msg.value;
for (uint256 i; i < outputs.length; i++) {
Expand All @@ -54,10 +55,17 @@ abstract contract OrderDestination {
// emit
emit Filled(outputs);
}

function fillPermit(Output[] memory outputs, Permit[] memory permits) external payable {
// first, execute token permissions to set token allowance
_permit(permits);
// then, fill orders
fill(outputs);
}
}

/// @notice Contract capable of registering initiation of intent-based Orders.
abstract contract OrderOrigin {
abstract contract OrderOrigin is PermitLib {
/// @notice Thrown when an Order is submitted with a deadline that has passed.
error OrderExpired();

Expand Down Expand Up @@ -86,7 +94,7 @@ abstract contract OrderOrigin {
/// @param outputs - The token amounts that must be received on their target chain(s) in order for the Order to be executed.
/// @custom:reverts OrderExpired if the deadline has passed.
/// @custom:emits Order if the transaction mines.
function initiate(uint256 deadline, Input[] memory inputs, Output[] memory outputs) external payable {
function initiate(uint256 deadline, Input[] memory inputs, Output[] memory outputs) public payable {
// check that the deadline hasn't passed
if (block.timestamp > deadline) revert OrderExpired();

Expand All @@ -97,6 +105,16 @@ abstract contract OrderOrigin {
emit Order(deadline, inputs, outputs);
}

function initiatePermit(Permit[] memory permits, uint256 deadline, Input[] memory inputs, Output[] memory outputs)
external
payable
{
// first, execute token permissions to set token allowance
_permit(permits);
// then, initiate the Order
initiate(deadline, inputs, outputs);
}

/// @notice Transfer the Order inputs to this contract, where they can be collected by the Order filler.
function _transferInputs(Input[] memory inputs) internal {
uint256 value = msg.value;
Expand Down
15 changes: 14 additions & 1 deletion src/Passage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
pragma solidity ^0.8.24;

import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {Permit, PermitLib} from "./Permit.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.
contract Passage {
contract Passage is PermitLib {
/// @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 @@ -106,6 +107,18 @@ contract Passage {
enterToken(defaultRollupChainId, rollupRecipient, token, amount);
}

/// @notice Allows ERC20 tokens to enter the rollup with a permit message.
function enterTokenPermit(
uint256 rollupChainId,
address rollupRecipient,
address token,
uint256 amount,
Permit memory permit
) external {
_permit(permit);
enterToken(rollupChainId, rollupRecipient, token, amount);
}

/// @notice Allows a special transaction to be sent to the rollup with sender == L1 msg.sender.
/// @dev Transaction is processed after normal rollup block execution.
/// @dev See `enterTransact` for docs.
Expand Down
29 changes: 29 additions & 0 deletions src/Permit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

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

struct Permit {
address token;
address owner;
address spender;
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}

abstract contract PermitLib {
function _permit(Permit memory permit) internal {
IERC20Permit(permit.token).permit(
permit.owner, permit.spender, permit.value, permit.deadline, permit.v, permit.r, permit.s
);
}

function _permit(Permit[] memory permits) internal {
for (uint256 i; i < permits.length; i++) {
_permit(permits[i]);
}
}
}