Skip to content

Commit 9926be6

Browse files
committed
added allocateAndRegister on OnChainAllocator
1 parent 36f9156 commit 9926be6

File tree

7 files changed

+288
-91
lines changed

7 files changed

+288
-91
lines changed

snapshots/ERC7683Allocator_open.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"open_simpleOrder": "184296"
2+
"open_simpleOrder": "184608"
33
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"openFor_simpleOrder_relayed": "168012",
3-
"openFor_simpleOrder_userHimself": "168012"
2+
"openFor_simpleOrder_relayed": "166882",
3+
"openFor_simpleOrder_userHimself": "166914"
44
}

src/allocators/ERC7683Allocator.sol

Lines changed: 103 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ import {BatchCompact, Lock} from '@uniswap/the-compact/types/EIP712Types.sol';
1414

1515
contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
1616
/// @notice The typehash of the OrderDataOnChain struct
17-
// keccak256("OrderDataOnChain(address arbiter,uint256 expires,Order order,uint200 targetBlock,uint56 maximumBlocksAfterTarget)
17+
// keccak256("OrderDataOnChain(Order order,uint256 expires)
1818
// Lock(bytes12 lockTag,address token,uint256 amount)
19-
// Order(Lock[] commitments,uint256 chainId,address tribunal,address recipient,address settlementToken,uint256 minimumAmount,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] decayCurve,bytes32 salt)")
19+
// Order(address arbiter,Lock[] commitments,uint256 chainId,address tribunal,address recipient,address settlementToken,uint256 minimumAmount,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] decayCurve,bytes32 salt,bytes32 qualification)")
2020
bytes32 public constant ORDERDATA_ONCHAIN_TYPEHASH =
21-
0x95d7f00c299b34a562258ba851472a8d9bd0d8a1b88fce3a37b7d27ca06e77c4;
21+
0x037a34e1ded3bcc84f59dfc185efc3553c509ebab317153a8dddefce2eaee6f0;
2222

2323
/// @notice The typehash of the OrderDataGasless struct
24-
// keccak256("OrderDataGasless(address arbiter,Order order)
24+
// keccak256("OrderDataGasless(Order order,bool deposit)
2525
// Lock(bytes12 lockTag,address token,uint256 amount)
26-
// Order(Lock[] commitments,uint256 chainId,address tribunal,address recipient,address settlementToken,uint256 minimumAmount,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] decayCurve,bytes32 salt)")
26+
// Order(address arbiter,Lock[] commitments,uint256 chainId,address tribunal,address recipient,address settlementToken,uint256 minimumAmount,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] decayCurve,bytes32 salt,bytes32 qualification)")
2727
bytes32 public constant ORDERDATA_GASLESS_TYPEHASH =
28-
0xdebd9e7866045b7f0ce8613ffbb31daa3fa5c6e6ac228316ba9f57fda63b7489;
28+
0x79e4af6feaa84a46fd69ed25e4595e9f6e8690ba3a6c564bfa235542f9faf55c;
2929

3030
/// @notice keccak256("BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Lock[] commitments,Mandate mandate)
3131
// Lock(bytes12 lockTag,address token,uint256 amount)
@@ -41,32 +41,49 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
4141
constructor(address compactContract_) OnChainAllocator(compactContract_) {}
4242

4343
/// @inheritdoc IOriginSettler
44-
function openFor(GaslessCrossChainOrder calldata order_, bytes calldata sponsorSignature_, bytes calldata)
45-
external
46-
{
44+
function openFor(
45+
GaslessCrossChainOrder calldata order_,
46+
bytes calldata sponsorSignature_,
47+
bytes calldata fillerData
48+
) external {
4749
// Check if orderDataType is the one expected by the allocator
4850
if (order_.orderDataType != ORDERDATA_GASLESS_TYPEHASH) {
4951
revert InvalidOrderDataType(order_.orderDataType, ORDERDATA_GASLESS_TYPEHASH);
5052
}
51-
/// TODO: Potentially useless check, since the allocator Id gets checked later.
5253
if (order_.originSettler != address(this)) {
5354
revert InvalidOriginSettler(order_.originSettler, address(this));
5455
}
56+
57+
// Decode the orderData
58+
(Order calldata orderData, uint32 deposit) = _decodeOrderData(order_.orderData);
59+
60+
uint160 caller = uint160(deposit * uint160(msg.sender)); // for a deposit, the nonce will be scoped to the caller + user
61+
bytes32 nonceIdentifier = _toNonceId(address(caller), order_.user);
62+
5563
// Early revert if the expected nonce is not the next nonce
56-
if (order_.nonce != nonces[order_.user] + 1) {
57-
revert InvalidNonce(order_.nonce, nonces[order_.user] + 1);
64+
if (order_.nonce != nonces[nonceIdentifier] + 1) {
65+
revert InvalidNonce(order_.nonce, nonces[nonceIdentifier] + 1);
5866
}
5967

60-
// Decode the orderData
61-
(, Order calldata orderData,,) = _decodeOrderData(order_.orderData, false);
68+
bytes32 qualification = bytes32(uint256(orderData.qualification) * deposit); // delete qualification if not a deposit
6269

6370
ResolvedCrossChainOrder memory resolvedOrder = _resolveOrder(
64-
order_.user, order_.nonce, order_.openDeadline, order_.fillDeadline, orderData, sponsorSignature_, 0, 0
71+
order_.user,
72+
order_.nonce,
73+
order_.openDeadline,
74+
order_.fillDeadline,
75+
orderData,
76+
sponsorSignature_,
77+
qualification
6578
);
6679

6780
bytes32 mandateHash = _mandateHash(orderData, order_.fillDeadline);
6881

69-
_open(order_.user, order_.openDeadline, orderData, sponsorSignature_, mandateHash, bytes32(0), resolvedOrder);
82+
if (deposit == 0) {
83+
_open(order_.user, order_.openDeadline, orderData, sponsorSignature_, mandateHash, resolvedOrder);
84+
} else {
85+
_openAndRegister(order_.user, order_.openDeadline, orderData, mandateHash, resolvedOrder);
86+
}
7087
}
7188

7289
/// @inheritdoc IOriginSettler
@@ -77,31 +94,21 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
7794
}
7895

7996
// Decode the orderData
80-
(uint32 expires, Order calldata orderData, uint200 targetBlock, uint56 maximumBlocksAfterTarget) =
81-
_decodeOrderData(order.orderData, true);
97+
(Order calldata orderData, uint32 expires) = _decodeOrderData(order.orderData);
8298

8399
bytes32 mandateHash = _mandateHash(orderData, order.fillDeadline);
84100

85101
ResolvedCrossChainOrder memory resolvedOrder = _resolveOrder(
86102
msg.sender,
87-
nonces[msg.sender] + 1,
103+
nonces[_toNonceId(address(0), msg.sender)] + 1,
88104
expires,
89105
order.fillDeadline,
90106
orderData,
91107
LibBytes.emptyCalldata(),
92-
targetBlock,
93-
maximumBlocksAfterTarget
108+
orderData.qualification
94109
);
95110

96-
_open(
97-
msg.sender,
98-
expires,
99-
orderData,
100-
LibBytes.emptyCalldata(),
101-
mandateHash,
102-
bytes32(abi.encodePacked(targetBlock, maximumBlocksAfterTarget)),
103-
resolvedOrder
104-
);
111+
_open(msg.sender, expires, orderData, LibBytes.emptyCalldata(), mandateHash, resolvedOrder);
105112
}
106113

107114
/// @inheritdoc IOriginSettler
@@ -114,17 +121,22 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
114121
if (order_.orderDataType != ORDERDATA_GASLESS_TYPEHASH) {
115122
revert InvalidOrderDataType(order_.orderDataType, ORDERDATA_GASLESS_TYPEHASH);
116123
}
117-
/// TODO: Potentially useless check, since the allocator Id gets checked later.
118124
if (order_.originSettler != address(this)) {
119125
revert InvalidOriginSettler(order_.originSettler, address(this));
120126
}
127+
128+
// Decode the orderData
129+
(Order calldata orderData, uint32 deposit) = _decodeOrderData(order_.orderData);
130+
131+
uint160 caller = uint160(deposit * uint160(msg.sender)); // for a deposit, the nonce will be scoped to the caller + user
132+
bytes32 nonceIdentifier = _toNonceId(address(caller), order_.user);
133+
121134
// Early revert if the expected nonce is not the next nonce
122-
if (order_.nonce != nonces[order_.user] + 1) {
123-
revert InvalidNonce(order_.nonce, nonces[order_.user] + 1);
135+
if (order_.nonce != nonces[nonceIdentifier] + 1) {
136+
revert InvalidNonce(order_.nonce, nonces[nonceIdentifier] + 1);
124137
}
125138

126-
// Decode the orderData
127-
(, Order calldata orderData,,) = _decodeOrderData(order_.orderData, false);
139+
bytes32 qualification = bytes32(uint256(orderData.qualification) * deposit);
128140

129141
return _resolveOrder(
130142
order_.user,
@@ -133,8 +145,7 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
133145
order_.fillDeadline,
134146
orderData,
135147
LibBytes.emptyCalldata(),
136-
0,
137-
0
148+
qualification
138149
);
139150
}
140151

@@ -146,18 +157,16 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
146157
}
147158

148159
// Decode the orderData
149-
(uint32 expires, Order calldata orderData, uint200 targetBlock, uint56 maximumBlocksAfterTarget) =
150-
_decodeOrderData(order.orderData, true);
160+
(Order calldata orderData, uint32 expires) = _decodeOrderData(order.orderData);
151161

152162
return _resolveOrder(
153163
msg.sender,
154-
nonces[msg.sender] + 1,
164+
nonces[_toNonceId(address(0), msg.sender)] + 1,
155165
expires,
156166
order.fillDeadline,
157167
orderData,
158168
LibBytes.emptyCalldata(),
159-
targetBlock,
160-
maximumBlocksAfterTarget
169+
orderData.qualification
161170
);
162171
}
163172

@@ -206,8 +215,18 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
206215
}
207216

208217
/// @inheritdoc IERC7683Allocator
209-
function checkNonce(uint256 nonce_, address sponsor_) external view returns (bool nonceValid) {
210-
return nonces[sponsor_] + 1 == nonce_;
218+
function checkNonce(GaslessCrossChainOrder calldata order_, address caller)
219+
external
220+
view
221+
returns (bool nonceValid)
222+
{
223+
(, uint32 deposit) = _decodeOrderData(order_.orderData);
224+
225+
caller = address(uint160(deposit * uint160(caller))); // for a deposit, the nonce will be scoped to the caller + user
226+
bytes32 nonceIdentifier = _toNonceId(caller, order_.user);
227+
228+
// Early revert if the expected nonce is not the next nonce
229+
return (order_.nonce == nonces[nonceIdentifier] + 1);
211230
}
212231

213232
/// @inheritdoc IERC7683Allocator
@@ -219,10 +238,9 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
219238
address sponsor,
220239
uint32 expires,
221240
Order calldata orderData,
222-
bytes calldata sponsorSignature_,
223-
bytes32 mandateHash_,
224-
bytes32 qualification_,
225-
ResolvedCrossChainOrder memory resolvedOrder_
241+
bytes calldata sponsorSignature,
242+
bytes32 mandateHash,
243+
ResolvedCrossChainOrder memory resolvedOrder
226244
) internal {
227245
// Register the allocation on chain
228246
(bytes32 claimHash, uint256 nonce) = allocateFor(
@@ -231,27 +249,54 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
231249
orderData.arbiter,
232250
expires,
233251
BATCH_COMPACT_WITNESS_TYPEHASH,
234-
mandateHash_,
235-
sponsorSignature_
252+
mandateHash,
253+
sponsorSignature
254+
);
255+
256+
if (sponsor == msg.sender && orderData.qualification != bytes32(0)) {
257+
qualifications[claimHash] = orderData.qualification;
258+
}
259+
260+
// Emit an open event
261+
emit Open(bytes32(nonce), resolvedOrder);
262+
}
263+
264+
function _openAndRegister(
265+
address sponsor,
266+
uint32 expires,
267+
Order calldata orderData,
268+
bytes32 mandateHash_,
269+
ResolvedCrossChainOrder memory resolvedOrder_
270+
) internal {
271+
// Register the allocation on chain
272+
(bytes32 claimHash, uint256[] memory registeredAmounts, uint256 nonce) = allocateAndRegister(
273+
sponsor, orderData.commitments, orderData.arbiter, expires, BATCH_COMPACT_WITNESS_TYPEHASH, mandateHash_
236274
);
237275

238-
qualifications[claimHash] = qualification_;
276+
for (uint256 i = 0; i < registeredAmounts.length; i++) {
277+
if (registeredAmounts[i] != orderData.commitments[i].amount) {
278+
// FOT tokens unsupported
279+
revert UnsupportedToken(orderData.commitments[i].token);
280+
}
281+
}
282+
283+
if (orderData.qualification != bytes32(0)) {
284+
qualifications[claimHash] = orderData.qualification;
285+
}
239286

240287
// Emit an open event
241288
emit Open(bytes32(nonce), resolvedOrder_);
242289
}
243290

244-
function _decodeOrderData(bytes calldata orderData, bool onChain)
291+
function _decodeOrderData(bytes calldata orderData)
245292
internal
246293
pure
247-
returns (uint32 expires, Order calldata order, uint200 targetBlock, uint56 maximumBlocksAfterTarget)
294+
returns (Order calldata order, uint32 additionalInput)
248295
{
249296
// orderData includes the OrderData(OnChain/Gasless) struct, and the nested Order struct.
250297
// 0x00: OrderDataOnChain.offset
251298
// 0x20: OrderDataOnChain.order.offset
252299
// 0x40: OrderDataOnChain.expires
253-
// 0x60: OrderDataOnChain.targetBlock
254-
// 0x80: OrderDataOnChain.maximumBlocksAfterTarget
255300

256301
// 0x00: OrderDataGasless.offset
257302
// 0x20: OrderDataGasless.order.offset
@@ -262,9 +307,7 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
262307
order := add(orderData.offset, add(s, 0x20)) // Add 0x20 since the OrderStruct is within the `OrderData...` struct
263308
if shr(64, or(s, or(l, orderData.offset))) { revert(l, 0x00) }
264309

265-
expires := mul(calldataload(add(orderData.offset, 0x40)), onChain)
266-
targetBlock := mul(calldataload(add(orderData.offset, 0x60)), onChain)
267-
maximumBlocksAfterTarget := mul(calldataload(add(orderData.offset, 0x80)), onChain)
310+
additionalInput := calldataload(add(orderData.offset, 0x40))
268311
}
269312
}
270313

@@ -275,8 +318,7 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
275318
uint32 fillDeadline,
276319
Order calldata orderData,
277320
bytes calldata sponsorSignature,
278-
uint200 targetBlock,
279-
uint56 maximumBlocksAfterTarget
321+
bytes32 qualification
280322
) internal view returns (ResolvedCrossChainOrder memory) {
281323
ResolvedCrossChainOrder memory resolvedOrder = ResolvedCrossChainOrder({
282324
user: sponsor,
@@ -319,7 +361,7 @@ contract ERC7683Allocator is OnChainAllocator, IERC7683Allocator {
319361
fillInstructions[0] = FillInstruction({
320362
destinationChainId: orderData.chainId,
321363
destinationSettler: _addressToBytes32(orderData.tribunal),
322-
originData: abi.encode(claim, mandate, targetBlock, maximumBlocksAfterTarget)
364+
originData: abi.encode(claim, mandate, uint200(bytes25(qualification)), uint56(uint256(qualification)))
323365
});
324366
resolvedOrder.fillInstructions = fillInstructions;
325367

0 commit comments

Comments
 (0)