1
1
// SPDX-License-Identifier: UNLICENSED
2
- pragma solidity 0.8.18 ;
2
+ pragma solidity ^ 0.8.0 ;
3
3
4
4
import {IWETH} from "./interfaces/IWETH.sol " ;
5
5
@@ -13,7 +13,6 @@ import {Ownable2StepUpgradeable} from
13
13
import {UUPSUpgradeable} from "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol " ;
14
14
import {Initializable} from "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol " ;
15
15
16
- import {ISwapRouter02} from "./interfaces/ISwapRouter02.sol " ;
17
16
import {SkipSwapRouter} from "./libraries/SkipSwapRouter.sol " ;
18
17
19
18
/// @title AxelarHandler
@@ -32,7 +31,7 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
32
31
error NonNativeCannotBeUnwrapped ();
33
32
error NativePaymentFailed ();
34
33
error WrappingNotEnabled ();
35
- error SwapFailed ();
34
+ error SwapFailedError ();
36
35
error InsufficientSwapOutput ();
37
36
error InsufficientNativeToken ();
38
37
error ETHSendFailed ();
@@ -45,8 +44,7 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
45
44
enum Commands {
46
45
SendToken,
47
46
SendNative,
48
- Swap,
49
- MultiSwap
47
+ Swap
50
48
}
51
49
52
50
bytes32 private _wETHSymbolHash;
@@ -58,7 +56,7 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
58
56
59
57
bytes32 public constant DISABLED_SYMBOL = keccak256 (abi.encodePacked ("DISABLED " ));
60
58
61
- ISwapRouter02 public swapRouter;
59
+ address public swapRouter;
62
60
63
61
bool internal reentrant;
64
62
@@ -96,7 +94,7 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
96
94
function setSwapRouter (address _swapRouter ) external onlyOwner {
97
95
if (_swapRouter == address (0 )) revert ZeroAddress ();
98
96
99
- swapRouter = ISwapRouter02 ( _swapRouter) ;
97
+ swapRouter = _swapRouter;
100
98
}
101
99
102
100
/// @notice Sends native currency to other chains through the axelar gateway.
@@ -230,73 +228,13 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
230
228
if (bytes (symbol).length == 0 ) revert EmptySymbol ();
231
229
232
230
// Get the address of the output token based on the symbol provided
233
- IERC20 outputToken = IERC20 ( _getTokenAddress (symbol) );
231
+ address outputToken = _getTokenAddress (symbol);
234
232
235
233
uint256 outputAmount;
236
234
if (inputToken == address (0 )) {
237
- // Native Token
238
- if (amount + gasPaymentAmount != msg .value ) revert InsufficientNativeToken ();
239
-
240
- // Get the contract's balances previous to the swap
241
- uint256 preInputBalance = address (this ).balance - msg .value ;
242
- uint256 preOutputBalance = outputToken.balanceOf (address (this ));
243
-
244
- // Call the swap router and perform the swap
245
- (bool success ,) = address (swapRouter).call {value: amount}(swapCalldata);
246
- if (! success) revert SwapFailed ();
247
-
248
- // Get the contract's balances after the swap
249
- uint256 postInputBalance = address (this ).balance;
250
- uint256 postOutputBalance = outputToken.balanceOf (address (this ));
251
-
252
- // Check that the contract's native token balance has increased
253
- if (preOutputBalance >= postOutputBalance) revert InsufficientSwapOutput ();
254
- outputAmount = postOutputBalance - preOutputBalance;
255
-
256
- // Refund the remaining ETH
257
- uint256 dust = postInputBalance - preInputBalance - gasPaymentAmount;
258
- if (dust != 0 ) {
259
- (bool ethSuccess ,) = msg .sender .call {value: dust}("" );
260
- if (! ethSuccess) revert ETHSendFailed ();
261
- }
262
-
263
- emit SwapSuccess (inputToken, address (outputToken), amount, outputAmount);
235
+ outputAmount = _swapAndRefundNative (amount, outputToken, gasPaymentAmount, swapCalldata);
264
236
} else {
265
- // ERC20 Token
266
- if (gasPaymentAmount != msg .value ) revert ();
267
-
268
- // Transfer input ERC20 tokens to the contract
269
- IERC20 token = IERC20 (inputToken);
270
- token.safeTransferFrom (msg .sender , address (this ), amount);
271
-
272
- // Approve the swap router to spend the input tokens
273
- token.safeApprove (address (swapRouter), amount);
274
-
275
- // Get the contract's balances previous to the swap
276
- uint256 preInputBalance = token.balanceOf (address (this ));
277
- uint256 preOutputBalance = outputToken.balanceOf (address (this ));
278
-
279
- // Call the swap router and perform the swap
280
- (bool success ,) = address (swapRouter).call (swapCalldata);
281
- if (! success) revert SwapFailed ();
282
-
283
- // Get the contract's balances after the swap
284
- uint256 dust = token.balanceOf (address (this )) + amount - preInputBalance;
285
- uint256 postOutputBalance = outputToken.balanceOf (address (this ));
286
-
287
- // Check that the contract's output token balance has increased
288
- if (preOutputBalance >= postOutputBalance) revert InsufficientSwapOutput ();
289
- outputAmount = postOutputBalance - preOutputBalance;
290
-
291
- // Refund the remaining amount
292
- if (dust != 0 ) {
293
- token.safeTransfer (msg .sender , dust);
294
-
295
- // Revoke approval
296
- token.safeApprove (address (swapRouter), 0 );
297
- }
298
-
299
- emit SwapSuccess (inputToken, address (outputToken), amount, outputAmount);
237
+ outputAmount = _swapAndRefund (amount, inputToken, outputToken, gasPaymentAmount, swapCalldata);
300
238
}
301
239
302
240
// Pay the gas for the GMP transfer
@@ -390,30 +328,13 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
390
328
391
329
_sendNative (token, amount, destination);
392
330
} else if (command == Commands.Swap) {
393
- (address destination , bool unwrapOut , bytes memory swap ) = abi.decode (data, (address , bool , bytes ));
394
-
395
- try SkipSwapRouter.swap (swapRouter, destination, tokenIn, amount, swap) returns (
396
- IERC20 tokenOut , uint256 amountOut
397
- ) {
398
- if (unwrapOut) {
399
- _sendNative (address (tokenOut), amountOut, destination);
400
- emit SwapSuccess (address (tokenIn), address (0 ), amount, amountOut);
401
- } else {
402
- _sendToken (address (tokenOut), amountOut, destination);
403
- emit SwapSuccess (address (tokenIn), address (tokenOut), amount, amountOut);
404
- }
405
- } catch {
406
- _sendToken (token, amount, destination);
407
- emit SwapFailed ();
408
- }
409
- } else if (command == Commands.MultiSwap) {
410
- (address destination , bool unwrapOut , bytes [] memory swaps ) = abi.decode (data, (address , bool , bytes []));
331
+ (address tokenOut , address destination , bytes memory swap ) = abi.decode (data, (address , address , bytes ));
411
332
412
- try SkipSwapRouter.multiSwap (swapRouter, destination, tokenIn, amount, swaps ) returns (
413
- IERC20 tokenOut , uint256 amountOut
333
+ try SkipSwapRouter.swap (swapRouter, destination, address ( tokenIn), tokenOut, amount, swap ) returns (
334
+ uint256 amountOut
414
335
) {
415
- if (unwrapOut ) {
416
- _sendNative ( address (tokenOut), amountOut, destination );
336
+ if (tokenOut == address ( 0 ) ) {
337
+ address (destination). call {value: amountOut}( "" );
417
338
emit SwapSuccess (address (tokenIn), address (0 ), amount, amountOut);
418
339
} else {
419
340
_sendToken (address (tokenOut), amountOut, destination);
@@ -428,6 +349,85 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
428
349
}
429
350
}
430
351
352
+ function _swapAndRefund (
353
+ uint256 amount ,
354
+ address inputToken ,
355
+ address outputToken ,
356
+ uint256 gasPaymentAmount ,
357
+ bytes memory swapCalldata
358
+ ) internal returns (uint256 outputAmount ) {
359
+ // ERC20 Token
360
+ if (gasPaymentAmount != msg .value ) revert ();
361
+
362
+ // Transfer input ERC20 tokens to the contract
363
+ IERC20 token = IERC20 (inputToken);
364
+ token.safeTransferFrom (msg .sender , address (this ), amount);
365
+
366
+ // Approve the swap router to spend the input tokens
367
+ token.safeApprove (address (swapRouter), amount);
368
+
369
+ // Get the contract's balances previous to the swap
370
+ uint256 preInputBalance = token.balanceOf (address (this ));
371
+ uint256 preOutputBalance = IERC20 (outputToken).balanceOf (address (this ));
372
+
373
+ // Call the swap router and perform the swap
374
+ (bool success ,) = address (swapRouter).call (swapCalldata);
375
+ if (! success) revert SwapFailedError ();
376
+
377
+ // Get the contract's balances after the swap
378
+ uint256 dust = token.balanceOf (address (this )) + amount - preInputBalance;
379
+ uint256 postOutputBalance = IERC20 (outputToken).balanceOf (address (this ));
380
+
381
+ // Check that the contract's output token balance has increased
382
+ if (preOutputBalance >= postOutputBalance) revert InsufficientSwapOutput ();
383
+ outputAmount = postOutputBalance - preOutputBalance;
384
+
385
+ // Refund the remaining amount
386
+ if (dust != 0 ) {
387
+ token.safeTransfer (msg .sender , dust);
388
+
389
+ // Revoke approval
390
+ token.safeApprove (address (swapRouter), 0 );
391
+ }
392
+
393
+ emit SwapSuccess (inputToken, address (outputToken), amount, outputAmount);
394
+ }
395
+
396
+ function _swapAndRefundNative (
397
+ uint256 amount ,
398
+ address outputToken ,
399
+ uint256 gasPaymentAmount ,
400
+ bytes memory swapCalldata
401
+ ) internal returns (uint256 outputAmount ) {
402
+ // Native Token
403
+ if (amount + gasPaymentAmount != msg .value ) revert InsufficientNativeToken ();
404
+
405
+ // Get the contract's balances previous to the swap
406
+ uint256 preInputBalance = address (this ).balance - msg .value ;
407
+ uint256 preOutputBalance = IERC20 (outputToken).balanceOf (address (this ));
408
+
409
+ // Call the swap router and perform the swap
410
+ (bool success ,) = address (swapRouter).call {value: amount}(swapCalldata);
411
+ if (! success) revert SwapFailedError ();
412
+
413
+ // Get the contract's balances after the swap
414
+ uint256 postInputBalance = address (this ).balance;
415
+ uint256 postOutputBalance = IERC20 (outputToken).balanceOf (address (this ));
416
+
417
+ // Check that the contract's native token balance has increased
418
+ if (preOutputBalance >= postOutputBalance) revert InsufficientSwapOutput ();
419
+ outputAmount = postOutputBalance - preOutputBalance;
420
+
421
+ // Refund the remaining ETH
422
+ uint256 dust = postInputBalance - preInputBalance - gasPaymentAmount;
423
+ if (dust != 0 ) {
424
+ (bool ethSuccess ,) = msg .sender .call {value: dust}("" );
425
+ if (! ethSuccess) revert ETHSendFailed ();
426
+ }
427
+
428
+ emit SwapSuccess (address (0 ), address (outputToken), amount, outputAmount);
429
+ }
430
+
431
431
function _sendToken (address token , uint256 amount , address destination ) internal {
432
432
IERC20 (token).safeTransfer (destination, amount);
433
433
}
0 commit comments