Skip to content

Commit 15a573e

Browse files
committed
Simple native order
1 parent 30ef3d1 commit 15a573e

File tree

2 files changed

+56
-86
lines changed

2 files changed

+56
-86
lines changed

contracts/extensions/NativeOrderFactory.sol

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,10 @@ contract NativeOrderFactory is Ownable, EIP712Alien {
5050
));
5151
}
5252

53-
function create(IOrderMixin.Order calldata makerOrder) external payable returns (address clone) {
54-
// Validate main order parameters
55-
if (makerOrder.maker.get() != msg.sender) revert OrderMakerShouldBeMsgSender(msg.sender, makerOrder.maker.get());
56-
address receiver = makerOrder.receiver.get();
57-
if (receiver == address(0) || receiver == address(this)) revert OrderReceiverShouldBeSetCorrectly(receiver);
58-
if (msg.value != makerOrder.makingAmount) revert OrderMakingAmountShouldBeEqualToMsgValue(makerOrder.makingAmount, msg.value);
59-
60-
bytes32 makerOrderHash = makerOrder.hash(_domainSeparatorV4());
61-
clone = IMPLEMENTATION.cloneDeterministic(makerOrderHash);
62-
NativeOrderImpl(payable(clone)).depositAndApprove{ value: msg.value }();
63-
64-
IOrderMixin.Order memory order = makerOrder;
65-
order.maker = Address.wrap(uint160(clone));
66-
bytes32 orderHash = order.hashMemory(_domainSeparatorV4());
53+
function create(bytes32 makerSalt, bytes32 orderHash, uint40 expiration) external payable returns (address clone) {
54+
bytes32 salt = keccak256(abi.encode(msg.sender, makerSalt));
55+
clone = IMPLEMENTATION.cloneDeterministic(salt);
56+
NativeOrderImpl(payable(clone)).deposit{ value: msg.value }(msg.sender, orderHash, expiration);
6757
emit NativeOrderCreated(msg.sender, orderHash, clone, msg.value);
6858
}
6959

contracts/extensions/NativeOrderImpl.sol

Lines changed: 52 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Errors } from "../libraries/Errors.sol";
1414
import { EIP712Alien } from "../mocks/EIP712Alien.sol";
1515
import { OrderLib, IOrderMixin } from "../OrderLib.sol";
1616

17+
// This contract is owning makers' funds for native orders
1718
contract NativeOrderImpl is IERC1271, EIP712Alien, OnlyWethReceiver {
1819
using Clones for address;
1920
using AddressLib for Address;
@@ -22,40 +23,45 @@ contract NativeOrderImpl is IERC1271, EIP712Alien, OnlyWethReceiver {
2223
using OrderLib for IOrderMixin.Order;
2324
using MakerTraitsLib for MakerTraits;
2425

25-
event NativeOrderCancelled(bytes32 orderHash, uint256 balance);
26-
event NativeOrderCancelledByResolver(bytes32 orderHash, uint256 balance, uint256 resolverReward);
26+
event NativeOrderCancelled(uint256 balance);
27+
event NativeOrderCancelledByResolver(uint256 balance, uint256 resolverReward);
2728

28-
error OnlyLimitOrderProtocolViolation(address sender, address limitOrderProtocol);
2929
error OnlyFactoryViolation(address sender, address factory);
30-
error OnlyMakerViolation(address sender, address maker);
30+
error OnlyMakerViolation(address sender, uint80 makerTail);
3131
error ResolverAccessTokenMissing(address resolver, address accessToken);
32-
error OrderIsIncorrect(address expected, address actual);
3332
error OrderShouldBeExpired(uint256 currentTime, uint256 expirationTime);
3433
error CanNotCancelForZeroBalance();
35-
error RescueFundsTooMuch(uint256 requested, uint256 available);
3634
error CancellationDelayViolation(uint256 timePassedSinceExpiration, uint256 requiredDelay);
35+
error WrongMakerArgument(address maker, uint80 expectedTail);
3736

3837
uint256 private constant _CANCEL_GAS_LOWER_BOUND = 70_000;
3938

4039
IWETH private immutable _WETH;
4140
address private immutable _LOP;
42-
address private immutable _IMPLEMENTATION = address(this);
4341
address private immutable _FACTORY;
4442
IERC20 private immutable _ACCESS_TOKEN;
4543
uint256 private immutable _CANCELLATION_DELAY;
4644

45+
struct Purpose {
46+
uint80 orderHashTail;
47+
uint80 makerTail;
48+
uint40 expiration;
49+
}
50+
51+
Purpose public purpose;
52+
4753
modifier onlyFactory {
4854
if (msg.sender != _FACTORY) revert OnlyFactoryViolation(msg.sender, _FACTORY);
4955
_;
5056
}
5157

52-
modifier onlyResolver {
53-
if (_ACCESS_TOKEN.balanceOf(msg.sender) == 0) revert ResolverAccessTokenMissing(msg.sender, address(_ACCESS_TOKEN));
58+
modifier onlyMaker {
59+
if (uint80(uint160(msg.sender)) != purpose.makerTail) revert OnlyMakerViolation(msg.sender, purpose.makerTail);
5460
_;
5561
}
5662

57-
modifier onlyMaker(address maker) {
58-
if (msg.sender != maker) revert OnlyMakerViolation(msg.sender, maker);
63+
modifier onlyResolver {
64+
if (_ACCESS_TOKEN.balanceOf(msg.sender) == 0) revert ResolverAccessTokenMissing(msg.sender, address(_ACCESS_TOKEN));
5965
_;
6066
}
6167

@@ -78,89 +84,63 @@ contract NativeOrderImpl is IERC1271, EIP712Alien, OnlyWethReceiver {
7884
_CANCELLATION_DELAY = cancellationDelay;
7985
}
8086

81-
function depositAndApprove() external payable onlyFactory {
87+
function deposit(address maker, bytes32 orderHash, uint40 expiration) external payable onlyFactory {
88+
purpose = Purpose({
89+
orderHashTail: uint80(uint256(orderHash)),
90+
makerTail: uint80(uint160(maker)),
91+
expiration: expiration
92+
});
8293
_WETH.safeDeposit(msg.value);
8394
_WETH.forceApprove(_LOP, msg.value);
8495
}
8596

86-
function isValidSignature(bytes32 hash, bytes calldata signature) external view returns(bytes4) {
87-
// Extract order from signature via calldata type casting
88-
IOrderMixin.Order calldata makerOrder;
89-
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
90-
makerOrder := signature.offset
97+
function isValidSignature(bytes32 hash, bytes calldata /* signature */) external view returns(bytes4) {
98+
uint80 orderHashTail = purpose.orderHashTail;
99+
uint256 expiration = purpose.expiration;
100+
if (uint80(uint256(hash)) != orderHashTail) {
101+
return 0xffffffff;
91102
}
92-
93-
// Check order args by CREATE2 salt validation
94-
bytes32 makerOrderHash = makerOrder.hash(_domainSeparatorV4());
95-
address clone = _IMPLEMENTATION.predictDeterministicAddress(makerOrderHash, _FACTORY);
96-
if (clone != address(this)) {
97-
return bytes4(0);
98-
}
99-
100-
// Check if patched order from signature matches LOP filling order
101-
bytes32 orderHash = _patchOrderMakerAndHash(makerOrder);
102-
if (orderHash != hash) {
103-
return bytes4(0);
103+
if (block.timestamp >= expiration) {
104+
return 0xffffffff;
104105
}
105-
106106
return this.isValidSignature.selector;
107107
}
108108

109-
function cancelOrder(IOrderMixin.Order calldata makerOrder) external onlyMaker(makerOrder.maker.get()) {
110-
uint256 balance = _cancelOrder(makerOrder, 0);
111-
bytes32 orderHash = _patchOrderMakerAndHash(makerOrder);
112-
emit NativeOrderCancelled(orderHash, balance);
109+
function cancelOrder() external onlyMaker {
110+
uint256 balance = _WETH.safeBalanceOf(address(this));
111+
_WETH.safeWithdrawTo(balance, msg.sender);
112+
emit NativeOrderCancelled(balance);
113113
}
114114

115-
function cancelExpiredOrderByResolver(IOrderMixin.Order calldata makerOrder, uint256 rewardLimit) external onlyResolver {
116-
uint256 orderExpiration = makerOrder.makerTraits.getExpirationTime();
117-
if (!makerOrder.makerTraits.isExpired()) revert OrderShouldBeExpired(block.timestamp, orderExpiration);
118-
119-
uint256 resolverReward = 0;
120-
if (rewardLimit > 0) {
121-
if (block.timestamp - orderExpiration < _CANCELLATION_DELAY) revert CancellationDelayViolation(block.timestamp - orderExpiration, _CANCELLATION_DELAY);
122-
resolverReward = Math.min(rewardLimit, block.basefee * _CANCEL_GAS_LOWER_BOUND * 1.1e18 / 1e18);
115+
function rescueFunds(address token, address to, uint256 amount) external onlyMaker {
116+
if (token == address(0)) {
117+
(bool success, ) = to.call{ value: amount }("");
118+
if (!success) revert Errors.ETHTransferFailed();
119+
} else {
120+
IERC20(token).safeTransfer(to, amount);
123121
}
124-
uint256 balance = _cancelOrder(makerOrder, resolverReward);
125-
bytes32 orderHash = _patchOrderMakerAndHash(makerOrder);
126-
emit NativeOrderCancelledByResolver(orderHash, balance, resolverReward);
127122
}
128123

129-
function _cancelOrder(IOrderMixin.Order calldata makerOrder, uint256 resolverReward) private returns(uint256 balance) {
130-
bytes32 makerOrderHash = makerOrder.hash(_domainSeparatorV4());
131-
address clone = _IMPLEMENTATION.predictDeterministicAddress(makerOrderHash, _FACTORY);
132-
if (clone != address(this)) revert OrderIsIncorrect(clone, address(this));
124+
function cancelExpiredOrderByResolver(address maker, uint256 rewardLimit) external onlyResolver {
125+
uint80 makerTail = purpose.makerTail;
126+
uint256 purposeExpiration = purpose.expiration;
127+
if (uint80(uint160(maker)) != makerTail) revert WrongMakerArgument(maker, makerTail);
128+
if (block.timestamp < purposeExpiration) revert OrderShouldBeExpired(block.timestamp, purposeExpiration);
133129

134-
balance = _WETH.safeBalanceOf(address(this));
130+
uint256 balance = _WETH.safeBalanceOf(address(this));
135131
if (balance == 0) revert CanNotCancelForZeroBalance();
136-
137-
_WETH.safeWithdraw(balance);
138-
if (resolverReward > 0) {
132+
uint256 resolverReward;
133+
if (rewardLimit > 0) {
134+
if (block.timestamp - purposeExpiration < _CANCELLATION_DELAY) revert CancellationDelayViolation(block.timestamp - purposeExpiration, _CANCELLATION_DELAY);
135+
resolverReward = Math.min(rewardLimit, block.basefee * _CANCEL_GAS_LOWER_BOUND * 1.1e18 / 1e18); // base fee + 10%
139136
balance -= resolverReward;
140137
(bool success, ) = msg.sender.call{ value: resolverReward }("");
141138
if (!success) revert Errors.ETHTransferFailed();
142139
}
143140
if (balance > 0) {
144-
(bool success, ) = makerOrder.maker.get().call{ value: balance }("");
141+
(bool success, ) = maker.call{ value: balance }("");
145142
if (!success) revert Errors.ETHTransferFailed();
146143
}
147-
}
148-
149-
function rescueFunds(address token, address to, uint256 amount) external onlyResolver {
150-
if (token == address(0)) {
151-
payable(to).transfer(amount);
152-
} else if (IWETH(token) == _WETH) {
153-
uint256 remainingOrderAmount = _WETH.allowance(address(this), _LOP);
154-
uint256 extraAmount = _WETH.safeBalanceOf(address(this)) - remainingOrderAmount;
155-
if (amount > extraAmount) revert RescueFundsTooMuch(amount, extraAmount);
156-
_WETH.safeTransfer(to, amount);
157-
} else {
158-
IERC20(token).safeTransfer(to, amount);
159-
}
160-
}
161-
162-
function _patchOrderMakerAndHash(IOrderMixin.Order memory order) private view returns(bytes32) {
163-
order.maker = Address.wrap(uint160(address(this)));
164-
return order.hashMemory(_domainSeparatorV4());
144+
emit NativeOrderCancelledByResolver(balance, resolverReward);
165145
}
166146
}

0 commit comments

Comments
 (0)