Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions contracts/exchange_handlers/BalancerV2Handler.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
pragma solidity 0.5.7;
pragma experimental ABIEncoderV2;

import "../lib/SafeMath.sol";
import "../lib/Math.sol";
import "../lib/Utils.sol";
import "../lib/AllowanceSetter.sol";
import "./ExchangeHandler.sol";
import "../lib/TotleControl.sol";

import "../lib/BalancerV2SwapLib.sol";

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";


interface WETH {
function deposit() external payable;
function withdraw(uint256 amount) external;
}

interface IVault{
function swap(
BalancerV2SwapLib.SingleSwap calldata singleSwap,
BalancerV2SwapLib.FundManagement calldata funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256);
}

interface BV2Pool {
function getPoolId() external returns (bytes32 _poolId);
function getVault() external returns (IVault _vault);
}


/// @title BalancerV2Handler
/// @notice Handles the all BalancerHandler trades for the primary contract
contract BalancerV2Handler is ExchangeHandler, AllowanceSetter {

/*
* State Variables
*/
WETH weth;
/*
* Types
*/

/// @notice Constructor
constructor(address _weth) public {
weth = WETH(_weth);
}

struct OrderData {
address pool;
address tokenIn;
address tokenOut;
uint256 maxOrderSpend;
}

event OrderPerformed(address caller, address pool, address tokenIn, address tokenOut, uint256 amountSpentOnOrder, uint256 amountReceivedFromOrder, uint256 timestamp);

/*
* Public functions
*/

/*
* Internal functions
*/

function getMaxToSpend(
uint256 targetAmount,
uint256 availableToSpend,
uint256 maxOrderSpend
) internal returns (uint256 max) {
max = Math.min(Math.min(availableToSpend, targetAmount), maxOrderSpend);
return max;
}

function performOrder(
bytes memory genericPayload,
uint256 availableToSpend,
uint256 targetAmount,

bool targetAmountIsSource
)
public
payable
returns (uint256 amountSpentOnOrder, uint256 amountReceivedFromOrder)
{
OrderData memory data = abi.decode(genericPayload, (OrderData));
IERC20(data.tokenIn).transferFrom(msg.sender, address(this), availableToSpend);

amountSpentOnOrder = getMaxToSpend(
targetAmount,
availableToSpend,
data.maxOrderSpend
);

if (data.tokenIn == address(weth)) {
weth.deposit.value(amountSpentOnOrder)();
}

uint256 prevContractAmount;
if (amountSpentOnOrder > 0) {
BV2Pool pool = BV2Pool(data.pool);
IVault vault = pool.getVault();

approveAddress(address(vault), data.tokenIn);
approveAddress(msg.sender, data.tokenOut);

bytes32 poolId = pool.getPoolId();

BalancerV2SwapLib.SingleSwap memory singleSwap = BalancerV2SwapLib.SingleSwap(
poolId,
BalancerV2SwapLib.SwapKind.GIVEN_IN,
IAsset(data.tokenIn),
IAsset(data.tokenOut),
amountSpentOnOrder,
""
);

BalancerV2SwapLib.FundManagement memory fundManagement = BalancerV2SwapLib.FundManagement(
address(this),
false,
address(this),
false
);

amountReceivedFromOrder = vault.swap( // Getting amountCalculated
singleSwap,
fundManagement,
0,
block.timestamp
);


}

if (amountSpentOnOrder < availableToSpend) {
if (data.tokenIn == address(weth)) {
msg.sender.transfer(availableToSpend - amountSpentOnOrder);
} else {
ERC20SafeTransfer.safeTransfer(
data.tokenIn,
msg.sender,
availableToSpend - amountSpentOnOrder
);
}
}

if (data.tokenOut == address(weth)) {
weth.withdraw(amountReceivedFromOrder);
msg.sender.transfer(amountReceivedFromOrder);
} else {
ERC20SafeTransfer.safeTransfer(
data.tokenOut,
msg.sender,
amountReceivedFromOrder
);
}

emit OrderPerformed(msg.sender, data.pool, data.tokenIn, data.tokenOut, amountSpentOnOrder, amountReceivedFromOrder, block.timestamp);

}

/*
* Payable fallback function
*/

function() external payable {}
}
70 changes: 70 additions & 0 deletions contracts/lib/BalancerV2SwapLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
pragma solidity 0.5.7;
pragma experimental ABIEncoderV2;


import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
* @dev This is an empty interface used to represent either ERC20-conforming token contracts or ETH (using the zero
* address sentinel value). We're just relying on the fact that `interface` can be used to declare new address-like
* types.
*
* This concept is unrelated to a Pool's Asset Managers.
*/
interface IAsset {
// solhint-disable-previous-line no-empty-blocks
}

library BalancerV2SwapLib {

enum SwapKind { GIVEN_IN, GIVEN_OUT }


/**
* @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on
* the `kind` value.
*
* `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).
* Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
IAsset assetIn;
IAsset assetOut;
uint256 amount;
bytes userData;
}

/**
* @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the
* `recipient` account.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20
* transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`
* must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of
* `joinPool`.
*
* If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of
* transferred. This matches the behavior of `exitPool`.
*
* Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a
* revert.
*/
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}



}


Loading