Skip to content

Commit a69da46

Browse files
committed
fix fillOrder approvals to hook contract
1 parent 7e51d17 commit a69da46

File tree

7 files changed

+56
-44
lines changed

7 files changed

+56
-44
lines changed

src/AsyncSwap.sol

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { AsyncFiller } from "@async-swap/libraries/AsyncFiller.sol";
88
import { AsyncOrder } from "@async-swap/types/AsyncOrder.sol";
99
import { CurrencySettler } from "@uniswap/v4-core/test/utils/CurrencySettler.sol";
1010
import { IPoolManager } from "v4-core/interfaces/IPoolManager.sol";
11+
import { IERC20Minimal } from "v4-core/interfaces/external/IERC20Minimal.sol";
1112
import { Hooks } from "v4-core/libraries/Hooks.sol";
1213
import { LPFeeLibrary } from "v4-core/libraries/LPFeeLibrary.sol";
1314
import { SafeCast } from "v4-core/libraries/SafeCast.sol";
@@ -131,13 +132,14 @@ contract AsyncSwap is BaseHook, IAsyncSwapAMM {
131132
}
132133

133134
/// @inheritdoc IAsyncSwapAMM
134-
function executeOrder(AsyncOrder calldata order, bytes calldata) external {
135+
function executeOrder(AsyncOrder calldata order, bytes calldata fillerData) external {
135136
address owner = order.owner;
136137
uint256 amountIn = order.amountIn;
137138
bool zeroForOne = order.zeroForOne;
138139
Currency currency0 = order.key.currency0;
139140
Currency currency1 = order.key.currency1;
140141
PoolId poolId = order.key.toId();
142+
address filler = abi.decode(fillerData, (address));
141143

142144
if (amountIn == 0) revert ZeroFillOrder();
143145

@@ -160,15 +162,15 @@ contract AsyncSwap is BaseHook, IAsyncSwapAMM {
160162
}
161163

162164
asyncOrders[poolId].asyncOrderAmount[owner][zeroForOne] -= amountToFill;
163-
/// TODO: check if this is needed, we could just burn
164-
poolManager.transfer(owner, currencyTake.toId(), amountToFill);
165+
/// we could also burn
166+
poolManager.transfer(filler, currencyTake.toId(), amountToFill);
165167
emit AsyncOrderFilled(poolId, owner, zeroForOne, amountToFill);
166168

167169
/// @dev Take currencyFill from filler
168170
/// @dev Hook may charge filler a hook fee
169171
/// TODO: If fee emit HookFee event
170-
currencyFill.take(poolManager, address(this), amountToFill, true);
171-
currencyFill.settle(poolManager, msg.sender, amountToFill, false); // transfer
172+
currencyFill.take(poolManager, owner, amountToFill, true);
173+
currencyFill.settle(poolManager, filler, amountToFill, false); // transfer
172174
}
173175

174176
/// @inheritdoc BaseHook

src/interfaces/IAsyncSwapAMM.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ interface IAsyncSwapAMM is IAsyncSwapOrder {
2020

2121
/// @notice Fill an async order in an Async Swap AMM.
2222
/// @param order The async order to be filled.
23-
/// @param userParams Additional data for the user.
23+
/// @param userParams data containe adderss of the filler.
2424
function executeOrder(AsyncOrder calldata order, bytes calldata userParams) external;
2525

2626
/// Fills async orders in batching mode, allowing multiple orders to be executed in a single transaction.

src/interfaces/IRouter.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ interface IRouter {
3838
/// Swaps tokens using an async order.
3939
/// @param order The async order to be placed.
4040
/// @param userData Additional data for the user, allowing user to specify an executor.
41-
function swap(AsyncOrder calldata order, bytes calldata userData) external;
41+
function swap(AsyncOrder calldata order, bytes calldata userData) external payable;
4242

4343
/// Fills an async order.
4444
/// @param order The async order to be filled.
4545
/// @param userData Additional data for the user, allowing user to specify an executor.
46-
function fillOrder(AsyncOrder calldata order, bytes calldata userData) external;
46+
function fillOrder(AsyncOrder calldata order, bytes calldata userData) external payable;
4747

4848
function withdraw(PoolKey memory key, bool zeroForOne, uint256 amount) external;
4949

src/router.sol

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ contract Router is IRouter {
5353
}
5454

5555
/// @inheritdoc IRouter
56-
function swap(AsyncOrder calldata order, bytes memory userData) external {
56+
function swap(AsyncOrder calldata order, bytes memory userData) external payable {
5757
address onBehalf = address(this);
5858
IAsyncSwapAMM.UserParams memory userParams = abi.decode(userData, (IAsyncSwapAMM.UserParams));
5959
require(userParams.executor == address(this), "Use router as your executor!");
@@ -66,7 +66,7 @@ contract Router is IRouter {
6666
}
6767

6868
/// @inheritdoc IRouter
69-
function fillOrder(AsyncOrder calldata order, bytes calldata) external {
69+
function fillOrder(AsyncOrder calldata order, bytes calldata) external payable {
7070
address onBehalf = address(this);
7171
assembly ("memory-safe") {
7272
tstore(USER_LOCATION, caller())
@@ -122,10 +122,20 @@ contract Router is IRouter {
122122
/// @dev FillingOrder
123123
if (action == 1) {
124124
SwapCallback memory orderData = abi.decode(data, (SwapCallback));
125-
Currency currency = orderData.order.zeroForOne ? orderData.order.key.currency1 : orderData.order.key.currency0;
126-
assert(IERC20Minimal(Currency.unwrap(currency)).transferFrom(user, asyncFiller, orderData.order.amountIn));
127-
assert(IERC20Minimal(Currency.unwrap(currency)).approve(address(HOOK), orderData.order.amountIn));
128-
HOOK.executeOrder(orderData.order, abi.encode(asyncFiller));
125+
Currency currencyFill;
126+
Currency currencyTake;
127+
if (orderData.order.zeroForOne) {
128+
currencyFill = orderData.order.key.currency1;
129+
currencyTake = orderData.order.key.currency0;
130+
} else {
131+
currencyFill = orderData.order.key.currency0;
132+
currencyTake = orderData.order.key.currency1;
133+
}
134+
// pay order
135+
// assert(IERC20Minimal(Currency.unwrap(currencyFill)).transferFrom(user, address(HOOK),
136+
// orderData.order.amountIn));
137+
HOOK.executeOrder(orderData.order, abi.encode(user));
138+
// currencyTake.take(POOLMANAGER, user, orderData.order.amountIn, false);
129139
}
130140

131141
/// @notice Handle withdrawals

test/AsyncFillerTest.t.sol

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ contract AsyncFillerTest is SetupHook {
6161
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: swapAmount, sqrtPrice: 2 ** 96 });
6262

6363
vm.startPrank(testExecutor);
64-
token1.approve(address(router), swapAmount);
65-
router.fillOrder(fillOrder, abi.encode(address(router)));
64+
token1.approve(address(hook), swapAmount);
65+
router.fillOrder(fillOrder, abi.encode(address(testExecutor)));
6666
vm.stopPrank();
6767

6868
// Verify order was filled
@@ -90,9 +90,9 @@ contract AsyncFillerTest is SetupHook {
9090
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: swapAmount, sqrtPrice: 2 ** 96 });
9191

9292
vm.startPrank(nonExecutor);
93-
token1.approve(address(router), swapAmount);
93+
token1.approve(address(hook), swapAmount);
9494
vm.expectRevert("Caller is valid not excutor");
95-
hook.executeOrder(fillOrder, "");
95+
hook.executeOrder(fillOrder, abi.encode(nonExecutor));
9696
vm.stopPrank();
9797
}
9898

@@ -115,8 +115,8 @@ contract AsyncFillerTest is SetupHook {
115115
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: fillAmount, sqrtPrice: 2 ** 96 });
116116

117117
vm.startPrank(testExecutor);
118-
token1.approve(address(router), fillAmount);
119-
router.fillOrder(fillOrder, abi.encode(address(router)));
118+
token1.approve(address(hook), fillAmount);
119+
router.fillOrder(fillOrder, abi.encode(address(testExecutor)));
120120
vm.stopPrank();
121121

122122
// Verify partial fill
@@ -142,9 +142,9 @@ contract AsyncFillerTest is SetupHook {
142142
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: excessFillAmount, sqrtPrice: 2 ** 96 });
143143

144144
vm.startPrank(testExecutor);
145-
token1.approve(address(router), excessFillAmount);
145+
token1.approve(address(hook), excessFillAmount);
146146
vm.expectRevert("Max fill order limit exceed");
147-
router.fillOrder(fillOrder, abi.encode(address(router)));
147+
router.fillOrder(fillOrder, abi.encode(address(testExecutor)));
148148
vm.stopPrank();
149149
}
150150

@@ -172,8 +172,8 @@ contract AsyncFillerTest is SetupHook {
172172
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: fillAmount, sqrtPrice: 2 ** 96 });
173173

174174
vm.startPrank(testExecutor);
175-
token1.approve(address(router), fillAmount);
176-
router.fillOrder(fillOrder, abi.encode(address(router)));
175+
token1.approve(address(hook), fillAmount);
176+
router.fillOrder(fillOrder, abi.encode(address(testExecutor)));
177177
vm.stopPrank();
178178

179179
// Verify fill
@@ -199,7 +199,7 @@ contract AsyncFillerTest is SetupHook {
199199

200200
vm.startPrank(testExecutor);
201201
vm.expectRevert("ZeroFillOrder()");
202-
hook.executeOrder(fillOrder, "");
202+
hook.executeOrder(fillOrder, abi.encode(testExecutor));
203203
vm.stopPrank();
204204
}
205205

@@ -233,10 +233,10 @@ contract AsyncFillerTest is SetupHook {
233233
AsyncOrder({ key: key, owner: testUser2, zeroForOne: true, amountIn: swapAmount2, sqrtPrice: 2 ** 96 });
234234

235235
vm.startPrank(testExecutor);
236-
token1.approve(address(router), swapAmount1 + swapAmount2);
236+
token1.approve(address(hook), swapAmount1 + swapAmount2);
237237

238-
router.fillOrder(fillOrder1, abi.encode(address(router)));
239-
router.fillOrder(fillOrder2, abi.encode(address(router)));
238+
router.fillOrder(fillOrder1, abi.encode(address(testExecutor)));
239+
router.fillOrder(fillOrder2, abi.encode(address(testExecutor)));
240240
vm.stopPrank();
241241

242242
// Verify both orders were filled
@@ -262,8 +262,8 @@ contract AsyncFillerTest is SetupHook {
262262
AsyncOrder({ key: key, owner: testUser, zeroForOne: false, amountIn: swapAmount, sqrtPrice: 2 ** 96 });
263263

264264
vm.startPrank(testExecutor);
265-
token0.approve(address(router), swapAmount);
266-
router.fillOrder(fillOrder, abi.encode(address(router)));
265+
token0.approve(address(hook), swapAmount);
266+
router.fillOrder(fillOrder, abi.encode(address(testExecutor)));
267267
vm.stopPrank();
268268

269269
// Verify order was filled

test/AsyncSwapEdgeCases.t.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ contract AsyncSwapEdgeCasesTest is SetupHook {
113113
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: 0, sqrtPrice: 2 ** 96 });
114114

115115
vm.expectRevert(AsyncFiller.ZeroFillOrder.selector);
116-
hook.executeOrder(order, "");
116+
hook.executeOrder(order, abi.encode(address(this)));
117117
}
118118

119119
function testExecuteOrdersMultiple() public {
@@ -153,8 +153,8 @@ contract AsyncSwapEdgeCasesTest is SetupHook {
153153
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: amountPerOrder, sqrtPrice: 2 ** 96 });
154154

155155
vm.startPrank(testExecutor);
156-
token1.approve(address(router), amountPerOrder);
157-
router.fillOrder(fillOrder, abi.encode(address(router)));
156+
token1.approve(address(hook), amountPerOrder);
157+
router.fillOrder(fillOrder, abi.encode(address(testExecutor)));
158158
vm.stopPrank();
159159
}
160160

test/RouterTest.t.sol

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ contract RouterTest is SetupHook {
6969
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: swapAmount, sqrtPrice: 2 ** 96 });
7070

7171
vm.startPrank(testUser2);
72-
token1.approve(address(router), swapAmount);
73-
router.fillOrder(fillOrder, "");
72+
token1.approve(address(hook), swapAmount);
73+
router.fillOrder(fillOrder, abi.encode(testUser2));
7474
vm.stopPrank();
7575

7676
// Verify order was filled
@@ -123,8 +123,8 @@ contract RouterTest is SetupHook {
123123
AsyncOrder({ key: key, owner: testUser, zeroForOne: false, amountIn: swapAmount, sqrtPrice: 2 ** 96 });
124124

125125
vm.startPrank(testUser2);
126-
token0.approve(address(router), swapAmount);
127-
router.fillOrder(fillOrder, "");
126+
token0.approve(address(hook), swapAmount);
127+
router.fillOrder(fillOrder, abi.encode(testUser2));
128128
vm.stopPrank();
129129

130130
// Verify order was filled
@@ -171,8 +171,8 @@ contract RouterTest is SetupHook {
171171
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: swapAmount1, sqrtPrice: 2 ** 96 });
172172

173173
vm.startPrank(testUser2);
174-
token1.approve(address(router), swapAmount1);
175-
router.fillOrder(fillOrder, "");
174+
token1.approve(address(hook), swapAmount1);
175+
router.fillOrder(fillOrder, abi.encode(testUser2));
176176
vm.stopPrank();
177177

178178
// Verify partial fill
@@ -183,8 +183,8 @@ contract RouterTest is SetupHook {
183183
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: swapAmount2, sqrtPrice: 2 ** 96 });
184184

185185
vm.startPrank(testUser2);
186-
token1.approve(address(router), swapAmount2);
187-
router.fillOrder(fillOrder2, "");
186+
token1.approve(address(hook), swapAmount2);
187+
router.fillOrder(fillOrder2, abi.encode(testUser2));
188188
vm.stopPrank();
189189

190190
// Verify complete fill
@@ -232,14 +232,14 @@ contract RouterTest is SetupHook {
232232
AsyncOrder({ key: key, owner: testUser, zeroForOne: true, amountIn: swapAmount, sqrtPrice: 2 ** 96 });
233233

234234
vm.startPrank(testUser2);
235-
token1.approve(address(router), swapAmount);
236-
router.fillOrder(fillOrder, "");
235+
token1.approve(address(hook), swapAmount);
236+
router.fillOrder(fillOrder, abi.encode(testUser2));
237237
vm.stopPrank();
238238

239239
// Verify balance changes
240240
assertEq(token1.balanceOf(testUser2), fillerBalance1Before - swapAmount);
241241
assertEq(token0.balanceOf(testUser2), fillerBalance0Before); // Should be unchanged
242-
assertEq(manager.balanceOf(testUser, currency0.toId()), uint256(swapAmount));
242+
assertEq(manager.balanceOf(testUser, currency1.toId()), uint256(swapAmount));
243243
}
244244

245245
function testFuzzSwapAmounts(uint256 amount, bool zeroForOne) public {

0 commit comments

Comments
 (0)