// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . pragma solidity ^0.7.6; pragma abicoder v2; import "./IERC20.sol"; /** * @dev Minimal interface for the Vault core contract only containing methods * used by Gnosis Protocol V2. Original source: * */ interface IVault { // Internal Balance // // Users can deposit tokens into the Vault, where they are allocated to their Internal Balance, and later // transferred or withdrawn. It can also be used as a source of tokens when joining Pools, as a destination // when exiting them, and as either when performing swaps. This usage of Internal Balance results in greatly reduced // gas costs when compared to relying on plain ERC20 transfers, leading to large savings for frequent users. // // Internal Balance management features batching, which means a single contract call can be used to perform multiple // operations of different kinds, with different senders and recipients, at once. /** * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer) * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as * it lets integrators reuse a user's Vault allowance. * * For each operation, if the caller is not `sender`, it must be an authorized relayer for them. */ function manageUserBalance(UserBalanceOp[] memory ops) external payable; /** * @dev Data for `manageUserBalance` operations, which include the possibility for ETH to be sent and received without manual WETH wrapping or unwrapping. */ struct UserBalanceOp { UserBalanceOpKind kind; IERC20 asset; uint256 amount; address sender; address payable recipient; } // There are four possible operations in `manageUserBalance`: // // - DEPOSIT_INTERNAL // Increases the Internal Balance of the `recipient` account by transferring tokens from the corresponding // `sender`. The sender must have allowed the Vault to use their tokens via `IERC20.approve()`. // // ETH can be used by passing the ETH sentinel value as the asset and forwarding ETH in the call: it will be wrapped // and deposited as WETH. Any ETH amount remaining will be sent back to the caller (not the sender, which is // relevant for relayers). // // Emits an `InternalBalanceChanged` event. // // // - WITHDRAW_INTERNAL // Decreases the Internal Balance of the `sender` account by transferring tokens to the `recipient`. // // ETH can be used by passing the ETH sentinel value as the asset. This will deduct WETH instead, unwrap it and send // it to the recipient as ETH. // // Emits an `InternalBalanceChanged` event. // // // - TRANSFER_INTERNAL // Transfers tokens from the Internal Balance of the `sender` account to the Internal Balance of `recipient`. // // Reverts if the ETH sentinel value is passed. // // Emits an `InternalBalanceChanged` event. // // // - TRANSFER_EXTERNAL // Transfers tokens from `sender` to `recipient`, using the Vault's ERC20 allowance. This is typically used by // relayers, as it lets them reuse a user's Vault allowance. // // Reverts if the ETH sentinel value is passed. // // Emits an `ExternalBalanceTransfer` event. enum UserBalanceOpKind { DEPOSIT_INTERNAL, WITHDRAW_INTERNAL, TRANSFER_INTERNAL, TRANSFER_EXTERNAL } // Swaps // // Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this, // they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be // aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote. // // The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence. // In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'), // and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out'). // More complex swaps, such as one token in to multiple tokens out can be achieved by batching together // individual swaps. // // There are two swap kinds: // - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the // `onSwap` hook) the amount of tokens out (to send to the recipient). // - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines // (via the `onSwap` hook) the amount of tokens in (to receive from the sender). // // Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with // the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated // tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended // swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at // the final intended token. // // In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal // Balance) after all individual swaps have been completed, and the net token balance change computed. This makes // certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost // much less gas than they would otherwise. // // It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple // Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only // updating the Pool's internal accounting). // // To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token // involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the // minimum amount of tokens to receive (by passing a negative value) is specified. // // Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after // this point in time (e.g. if the transaction failed to be included in a block promptly). // // If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do // the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be // passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the // same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers). // // Finally, Internal Balance can be used when either sending or receiving tokens. enum SwapKind { GIVEN_IN, GIVEN_OUT } /** * @dev Performs a swap with a single Pool. * * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens * taken from the Pool, which must be greater than or equal to `limit`. * * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens * sent to the Pool, which must be less than or equal to `limit`. * * Internal Balance usage and the recipient are determined by the `funds` struct. * * Emits a `Swap` event. */ function swap( SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline ) external payable returns (uint256); /** * @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; IERC20 assetIn; IERC20 assetOut; uint256 amount; bytes userData; } /** * @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either * the amount of tokens sent to or received from the Pool, depending on the `kind` value. * * Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the * Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at * the same index in the `assets` array. * * Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a * Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or * `amountOut` depending on the swap kind. * * Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out * of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal * the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`. * * The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses, * or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and * out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to * or unwrapped from WETH by the Vault. * * Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies * the minimum or maximum amount of each token the vault is allowed to transfer. * * `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the * equivalent `swap` call. * * Emits `Swap` events. */ function batchSwap( SwapKind kind, BatchSwapStep[] memory swaps, IERC20[] memory assets, FundManagement memory funds, int256[] memory limits, uint256 deadline ) external payable returns (int256[] memory); /** * @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the * `assets` array passed to that function, and ETH assets are converted to WETH. * * If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out * from the previous swap, depending on the swap kind. * * 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 BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; 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; } }