Skip to content

Commit f6d3a3e

Browse files
authored
feat: balancer v3 router gateway (#151)
1 parent 1449dc8 commit f6d3a3e

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// Gearbox Protocol. Generalized leverage for DeFi protocols
3+
// (c) Gearbox Foundation, 2024.
4+
pragma solidity ^0.8.23;
5+
6+
import {IBalancerV3Router} from "../../integrations/balancer/IBalancerV3Router.sol";
7+
8+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
9+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
10+
11+
interface IPermit2 {
12+
function approve(address token, address spender, uint160 amount, uint48 expiration) external;
13+
}
14+
15+
/// @title BalancerV3RouterGateway
16+
/// @dev This is connector contract to allow Gearbox adapters to swap through the Balancer V3 Router.
17+
/// Since the router requires the caller to approve inputs in Permit2, we need an intermediate contract,
18+
/// which will be approved to spend the inputs and then call the Permit2 and the router.
19+
contract BalancerV3RouterGateway is IBalancerV3Router {
20+
using SafeERC20 for IERC20;
21+
22+
address public immutable balancerV3Router;
23+
address public immutable permit2;
24+
25+
constructor(address _balancerV3Router, address _permit2) {
26+
balancerV3Router = _balancerV3Router;
27+
permit2 = _permit2;
28+
}
29+
30+
function swapSingleTokenExactIn(
31+
address pool,
32+
IERC20 tokenIn,
33+
IERC20 tokenOut,
34+
uint256 exactAmountIn,
35+
uint256 minAmountOut,
36+
uint256 deadline,
37+
bool wethIsEth,
38+
bytes calldata userData
39+
) external returns (uint256 amountOut) {
40+
tokenIn.safeTransferFrom(msg.sender, address(this), exactAmountIn);
41+
tokenIn.safeApprove(permit2, exactAmountIn);
42+
IPermit2(permit2).approve(address(tokenIn), balancerV3Router, uint160(exactAmountIn), uint48(block.timestamp));
43+
44+
IBalancerV3Router(balancerV3Router).swapSingleTokenExactIn(
45+
pool, tokenIn, tokenOut, exactAmountIn, minAmountOut, deadline, wethIsEth, userData
46+
);
47+
48+
amountOut = _transferBalance(tokenOut);
49+
50+
tokenIn.safeApprove(permit2, 1);
51+
52+
return amountOut;
53+
}
54+
55+
/// @dev Transfers the current balance of a token to sender (minus 1 for gas savings) and returns the amount transferred
56+
/// @param token Token to transfer
57+
function _transferBalance(IERC20 token) internal returns (uint256 transferredAmount) {
58+
uint256 balance = token.balanceOf(address(this));
59+
if (balance > 1) {
60+
unchecked {
61+
token.safeTransfer(msg.sender, balance - 1);
62+
}
63+
return balance - 1;
64+
}
65+
return 0;
66+
}
67+
}

0 commit comments

Comments
 (0)