Files
smom-dbis-138/contracts/bridge/trustless/adapters/BalancerRouteExecutorAdapter.sol

78 lines
2.8 KiB
Solidity
Raw Normal View History

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/IBalancerVault.sol";
import "../RouteTypesV2.sol";
import "../interfaces/IRouteExecutorAdapter.sol";
contract BalancerRouteExecutorAdapter is IRouteExecutorAdapter {
using SafeERC20 for IERC20;
function validate(
RouteTypesV2.RouteLeg calldata leg
) external pure override returns (bool ok, string memory reason) {
if (leg.provider != RouteTypesV2.Provider.Balancer) {
return (false, "BalancerRouteExecutorAdapter: invalid provider");
}
if (leg.target == address(0)) {
return (false, "BalancerRouteExecutorAdapter: zero target");
}
if (leg.providerData.length != 32) {
return (false, "BalancerRouteExecutorAdapter: invalid providerData");
}
return (true, "");
}
function quote(
RouteTypesV2.RouteLeg calldata leg,
uint256 amountIn
) external view override returns (uint256 amountOut, uint256 gasEstimate) {
bytes32 poolId = abi.decode(leg.providerData, (bytes32));
(address[] memory tokens, uint256[] memory balances,) = IBalancerVault(leg.target).getPoolTokens(poolId);
uint256 inIndex = type(uint256).max;
uint256 outIndex = type(uint256).max;
for (uint256 i = 0; i < tokens.length; i++) {
if (tokens[i] == leg.tokenIn) inIndex = i;
if (tokens[i] == leg.tokenOut) outIndex = i;
}
if (inIndex != type(uint256).max && outIndex != type(uint256).max && balances[inIndex] > 0) {
uint256 grossOut = (amountIn * balances[outIndex]) / balances[inIndex];
amountOut = (grossOut * 9950) / 10000;
}
gasEstimate = 230000;
}
function execute(
RouteTypesV2.RouteLeg calldata leg,
uint256 amountIn
) external override returns (uint256 amountOut) {
bytes32 poolId = abi.decode(leg.providerData, (bytes32));
IERC20(leg.tokenIn).forceApprove(leg.target, 0);
IERC20(leg.tokenIn).forceApprove(leg.target, amountIn);
amountOut = IBalancerVault(leg.target).swap(
IBalancerVault.SingleSwap({
poolId: poolId,
kind: IBalancerVault.SwapKind.GIVEN_IN,
assetIn: leg.tokenIn,
assetOut: leg.tokenOut,
amount: amountIn,
userData: ""
}),
IBalancerVault.FundManagement({
sender: address(this),
fromInternalBalance: false,
recipient: payable(msg.sender),
toInternalBalance: false
}),
leg.minAmountOut,
block.timestamp + 300
);
}
}