Skip to content

Commit

Permalink
New router library
Browse files Browse the repository at this point in the history
  • Loading branch information
wirew0lf committed Aug 15, 2024
1 parent 81c9b10 commit 18ffc6b
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 234 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
12 changes: 0 additions & 12 deletions AxelarHandler/.gitmodules

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"transactions": [
{
"hash": null,
"transactionType": "CREATE2",
"contractName": "BytesLib",
"contractAddress": "0xbfb201a128d08c99a6228938415b02d20b6ec4ad",
"function": null,
"arguments": null,
"transaction": {
"from": "0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38",
"to": "0x4e59b44847b379578588920ca78fbf26c0b4956c",
"gas": "0x27fab",
"input": "0x000000000000000000000000000000000000000000000000000000000000000061012b61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063593b79fe146038575b600080fd5b60676043366004607b565b604080516001600160a01b0392909216600560a21b18601483015260348201905290565b6040516072919060a9565b60405180910390f35b600060208284031215608c57600080fd5b81356001600160a01b038116811460a257600080fd5b9392505050565b600060208083528351808285015260005b8181101560d45785810183015185820160400152820160ba565b506000604082860101526040601f19601f830116850101925050509291505056fea26469706673582212202001b5e1dbec67ed81daef4e82e5dc66748bca332df0db2a80f4ac32bc7eda7664736f6c63430008120033",
"nonce": "0x0",
"chainId": "0x1"
},
"additionalContracts": [],
"isFixedGasLimit": false
}
],
"receipts": [],
"libraries": [
"src/libraries/Path.sol:BytesLib:0xBfB201a128D08C99a6228938415B02D20b6Ec4ad"
],
"pending": [],
"returns": {},
"timestamp": 1723057712,
"chain": 1,
"commit": "502ef75"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"transactions": [
{
"hash": null,
"transactionType": "CREATE2",
"contractName": "BytesLib",
"contractAddress": "0xbfb201a128d08c99a6228938415b02d20b6ec4ad",
"function": null,
"arguments": null,
"transaction": {
"from": "0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38",
"to": "0x4e59b44847b379578588920ca78fbf26c0b4956c",
"gas": "0x27fab",
"input": "0x000000000000000000000000000000000000000000000000000000000000000061012b61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063593b79fe146038575b600080fd5b60676043366004607b565b604080516001600160a01b0392909216600560a21b18601483015260348201905290565b6040516072919060a9565b60405180910390f35b600060208284031215608c57600080fd5b81356001600160a01b038116811460a257600080fd5b9392505050565b600060208083528351808285015260005b8181101560d45785810183015185820160400152820160ba565b506000604082860101526040601f19601f830116850101925050509291505056fea26469706673582212202001b5e1dbec67ed81daef4e82e5dc66748bca332df0db2a80f4ac32bc7eda7664736f6c63430008120033",
"nonce": "0x0",
"chainId": "0x1"
},
"additionalContracts": [],
"isFixedGasLimit": false
}
],
"receipts": [],
"libraries": [
"src/libraries/Path.sol:BytesLib:0xBfB201a128D08C99a6228938415B02D20b6Ec4ad"
],
"pending": [],
"returns": {},
"timestamp": 1723057941,
"chain": 1,
"commit": "502ef75"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"transactions": [
{
"hash": null,
"transactionType": "CREATE2",
"contractName": "BytesLib",
"contractAddress": "0xbfb201a128d08c99a6228938415b02d20b6ec4ad",
"function": null,
"arguments": null,
"transaction": {
"from": "0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38",
"to": "0x4e59b44847b379578588920ca78fbf26c0b4956c",
"gas": "0x27fab",
"input": "0x000000000000000000000000000000000000000000000000000000000000000061012b61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063593b79fe146038575b600080fd5b60676043366004607b565b604080516001600160a01b0392909216600560a21b18601483015260348201905290565b6040516072919060a9565b60405180910390f35b600060208284031215608c57600080fd5b81356001600160a01b038116811460a257600080fd5b9392505050565b600060208083528351808285015260005b8181101560d45785810183015185820160400152820160ba565b506000604082860101526040601f19601f830116850101925050509291505056fea26469706673582212202001b5e1dbec67ed81daef4e82e5dc66748bca332df0db2a80f4ac32bc7eda7664736f6c63430008120033",
"nonce": "0x0",
"chainId": "0x1"
},
"additionalContracts": [],
"isFixedGasLimit": false
}
],
"receipts": [],
"libraries": [
"src/libraries/Path.sol:BytesLib:0xBfB201a128D08C99a6228938415B02D20b6Ec4ad"
],
"pending": [],
"returns": {},
"timestamp": 1723057941,
"chain": 1,
"commit": "502ef75"
}
247 changes: 25 additions & 222 deletions AxelarHandler/src/AxelarHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ import {UUPSUpgradeable} from "lib/openzeppelin-contracts-upgradeable/contracts/
import {Initializable} from "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";

import {ISwapRouter02} from "./interfaces/ISwapRouter02.sol";
import {BytesLib, Path} from "./libraries/Path.sol";
import {SkipSwapRouter} from "./libraries/SkipSwapRouter.sol";

/// @title AxelarHandler
/// @notice allows to send and receive tokens to/from other chains through axelar gateway while wrapping the native tokens.
/// @author Skip Protocol.
contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable, UUPSUpgradeable {
using SafeERC20 for IERC20;
using Path for bytes;

error EmptySymbol();
error NativeSentDoesNotMatchAmounts();
Expand All @@ -43,7 +42,8 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
enum Commands {
SendToken,
SendNative,
Swap
Swap,
MultiSwap
}

bytes32 private _wETHSymbolHash;
Expand Down Expand Up @@ -388,34 +388,31 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
_sendToken(token, amount, destination);
}
} else if (command == Commands.Swap) {
(address destination, uint256 amountOutMin, bool unwrapOut, bytes[] memory swaps) =
abi.decode(data, (address, uint256, bool, bytes[]));

uint256 length = swaps.length;
for (uint256 i; i < length; ++i) {
(uint8 swapFunction, bytes memory swapPayload) = abi.decode(swaps[i], (uint8, bytes));

if (swapFunction == uint8(0)) {
(token, amount) = _exactInputSingleSwap(token, destination, amount, swapPayload);
} else if (swapFunction == uint8(1)) {
(token, amount) = _exactInputSwap(token, destination, amount, swapPayload);
} else if (swapFunction == uint8(2)) {
(token, amount) = _exactTokensForTokensSwap(token, destination, amount, swapPayload);
} else if (swapFunction == uint8(3)) {
(token, amount) = _exactOutputSingleSwap(token, destination, amount, swapPayload);
} else if (swapFunction == uint8(4)) {
(token, amount) = _exactOutputSwap(token, destination, amount, swapPayload);
} else if (swapFunction == uint8(5)) {
(token, amount) = _tokensForExactTokensSwap(token, destination, amount, swapPayload);
(address destination, bool unwrapOut, bytes memory swap) = abi.decode(data, (address, bool, bytes));

try SkipSwapRouter.swap(swapRouter, destination, tokenIn, amount, swap) returns (
IERC20 tokenOut, uint256 amountOut
) {
if (unwrapOut && address(tokenOut) == _getTokenAddress(wETHSymbol)) {
_sendNative(address(tokenOut), amountOut, destination);
} else {
revert FunctionCodeNotSupported();
_sendToken(address(tokenOut), amountOut, destination);
}
} catch {
_sendToken(token, amount, destination);
}

if (amount < amountOutMin) revert InsufficientSwapOutput();
if (unwrapOut && token == _getTokenAddress(wETHSymbol)) {
_sendNative(token, amount, destination);
} else {
} else if (command == Commands.MultiSwap) {
(address destination, bool unwrapOut, bytes[] memory swaps) = abi.decode(data, (address, bool, bytes[]));

try SkipSwapRouter.multiSwap(swapRouter, destination, tokenIn, amount, swaps) returns (
IERC20 tokenOut, uint256 amountOut
) {
if (unwrapOut && address(tokenOut) == _getTokenAddress(wETHSymbol)) {
_sendNative(address(tokenOut), amountOut, destination);
} else {
_sendToken(address(tokenOut), amountOut, destination);
}
} catch {
_sendToken(token, amount, destination);
}
} else {
Expand All @@ -440,199 +437,5 @@ contract AxelarHandler is AxelarExecutableUpgradeable, Ownable2StepUpgradeable,
}
}

function _exactInputSingleSwap(address token, address destination, uint256 amount, bytes memory data)
internal
returns (address tokenOut, uint256 amountOut)
{
ISwapRouter02.ExactInputSingleParams memory params;
(tokenOut, params.fee, params.sqrtPriceLimitX96) = abi.decode(data, (address, uint24, uint160));

params.tokenIn = token;
params.tokenOut = tokenOut;
params.amountIn = amount;
params.recipient = address(this);

IERC20 tokenSwapIn = IERC20(token);
IERC20 tokenSwapOut = IERC20(tokenOut);

uint256 preBalIn = tokenSwapIn.balanceOf(address(this)) - amount;
uint256 preBalOut = tokenSwapOut.balanceOf(address(this));

tokenSwapIn.safeApprove(address(swapRouter), amount);
swapRouter.exactInputSingle(params);

uint256 dustIn = tokenSwapIn.balanceOf(address(this)) - preBalIn;
amountOut = tokenSwapOut.balanceOf(address(this)) - preBalOut;

if (dustIn != 0) {
tokenSwapIn.safeApprove(address(swapRouter), 0);
tokenSwapIn.safeTransfer(destination, dustIn);
}
}

function _exactInputSwap(address token, address destination, uint256 amount, bytes memory data)
internal
returns (address tokenOut, uint256 amountOut)
{
ISwapRouter02.ExactInputParams memory params;
params.path = data;

params.recipient = address(this);
params.amountIn = amount;

(address tokenA,,) = params.path.decodeFirstPool();

if (tokenA != token) {
bytes memory tokenReplace = BytesLib.toBytes(token);
params.path = BytesLib.concat(tokenReplace, BytesLib.slice(params.path, 20, params.path.length - 20));
}

(, tokenOut,) = params.path.decodeLastPool();

IERC20 tokenSwapIn = IERC20(token);
IERC20 tokenSwapOut = IERC20(tokenOut);

uint256 preBalIn = tokenSwapIn.balanceOf(address(this)) - amount;
uint256 preBalOut = tokenSwapOut.balanceOf(address(this));

tokenSwapIn.safeApprove(address(swapRouter), amount);
swapRouter.exactInput(params);

uint256 dustIn = tokenSwapIn.balanceOf(address(this)) - preBalIn;
amountOut = tokenSwapOut.balanceOf(address(this)) - preBalOut;

if (dustIn != 0) {
tokenSwapIn.safeApprove(address(swapRouter), 0);
tokenSwapIn.safeTransfer(destination, dustIn);
}
}

function _exactOutputSingleSwap(address token, address destination, uint256 amount, bytes memory data)
internal
returns (address tokenOut, uint256 amountOut)
{
ISwapRouter02.ExactOutputSingleParams memory params;
(tokenOut, amountOut, params.fee, params.sqrtPriceLimitX96) =
abi.decode(data, (address, uint256, uint24, uint160));

params.tokenIn = token;
params.tokenOut = tokenOut;
params.recipient = address(this);
params.amountOut = amountOut;
params.amountInMaximum = amount;

IERC20 tokenSwapIn = IERC20(token);
IERC20 tokenSwapOut = IERC20(tokenOut);

uint256 preBalIn = tokenSwapIn.balanceOf(address(this)) - amount;
uint256 preBalOut = tokenSwapOut.balanceOf(address(this));

tokenSwapIn.safeApprove(address(swapRouter), amount);
swapRouter.exactOutputSingle(params);

uint256 dustIn = tokenSwapIn.balanceOf(address(this)) - preBalIn;
amountOut = tokenSwapOut.balanceOf(address(this)) - preBalOut;

if (dustIn != 0) {
tokenSwapIn.safeApprove(address(swapRouter), 0);
tokenSwapIn.safeTransfer(destination, dustIn);
}
}

function _exactOutputSwap(address token, address destination, uint256 amount, bytes memory data)
internal
returns (address tokenOut, uint256 amountOut)
{
ISwapRouter02.ExactOutputParams memory params;
(amountOut, params.path) = abi.decode(data, (uint256, bytes));

params.recipient = address(this);
params.amountOut = amountOut;
params.amountInMaximum = amount;

(, address tokenB,) = params.path.decodeLastPool();

if (tokenB != token) {
bytes memory tokenReplace = BytesLib.toBytes(token);
params.path = BytesLib.concat(BytesLib.slice(params.path, 0, params.path.length - 20), tokenReplace);
}

(tokenOut,,) = params.path.decodeFirstPool();

IERC20 tokenSwapIn = IERC20(token);
IERC20 tokenSwapOut = IERC20(tokenOut);

uint256 preBalIn = tokenSwapIn.balanceOf(address(this)) - amount;
uint256 preBalOut = tokenSwapOut.balanceOf(address(this));

tokenSwapIn.safeApprove(address(swapRouter), amount);
swapRouter.exactOutput(params);

uint256 dustIn = tokenSwapIn.balanceOf(address(this)) - preBalIn;
amountOut = tokenSwapOut.balanceOf(address(this)) - preBalOut;

if (dustIn != 0) {
tokenSwapIn.safeApprove(address(swapRouter), 0);
tokenSwapIn.safeTransfer(destination, dustIn);
}
}

function _exactTokensForTokensSwap(address token, address destination, uint256 amount, bytes memory data)
internal
returns (address tokenOut, uint256 amountOut)
{
(address[] memory path) = abi.decode(data, (address[]));

path[0] == token;

tokenOut = path[path.length - 1];

IERC20 tokenSwapIn = IERC20(token);
IERC20 tokenSwapOut = IERC20(tokenOut);

uint256 preBalIn = tokenSwapIn.balanceOf(address(this)) - amount;
uint256 preBalOut = tokenSwapOut.balanceOf(address(this));

tokenSwapIn.safeApprove(address(swapRouter), amount);
swapRouter.swapExactTokensForTokens(amount, 0, path, address(this));

uint256 dustIn = tokenSwapIn.balanceOf(address(this)) - preBalIn;
amountOut = tokenSwapOut.balanceOf(address(this)) - preBalOut;

if (dustIn != 0) {
tokenSwapIn.safeApprove(address(swapRouter), 0);
tokenSwapIn.safeTransfer(destination, dustIn);
}
}

function _tokensForExactTokensSwap(address token, address destination, uint256 amount, bytes memory data)
internal
returns (address tokenOut, uint256 amountOut)
{
address[] memory path;
(amountOut, path) = abi.decode(data, (uint256, address[]));

path[0] == token;

tokenOut = path[path.length - 1];

IERC20 tokenSwapIn = IERC20(token);
IERC20 tokenSwapOut = IERC20(tokenOut);

uint256 preBalIn = tokenSwapIn.balanceOf(address(this)) - amount;
uint256 preBalOut = tokenSwapOut.balanceOf(address(this));

tokenSwapIn.safeApprove(address(swapRouter), amount);
swapRouter.swapTokensForExactTokens(amountOut, amount, path, address(this));

uint256 dustIn = tokenSwapIn.balanceOf(address(this)) - preBalIn;
amountOut = tokenSwapOut.balanceOf(address(this)) - preBalOut;

if (dustIn != 0) {
tokenSwapIn.safeApprove(address(swapRouter), 0);
tokenSwapIn.safeTransfer(destination, dustIn);
}
}

function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
Loading

0 comments on commit 18ffc6b

Please sign in to comment.