Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 8 from a total of 8 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Execute Flash Lo... | 21957686 | 365 days ago | IN | 0 ETH | 0.00053006 | ||||
| Execute Flash Lo... | 21957680 | 365 days ago | IN | 0 ETH | 0.00050699 | ||||
| Execute Flash Lo... | 21957651 | 365 days ago | IN | 0 ETH | 0.00051877 | ||||
| Execute Flash Lo... | 21954040 | 366 days ago | IN | 0 ETH | 0.00103998 | ||||
| Execute Flash Lo... | 21954004 | 366 days ago | IN | 0 ETH | 0.00120741 | ||||
| Execute Flash Lo... | 21953980 | 366 days ago | IN | 0 ETH | 0.00048636 | ||||
| Execute Flash Lo... | 21953915 | 366 days ago | IN | 0 ETH | 0.00058462 | ||||
| Execute Flash Lo... | 21953822 | 366 days ago | IN | 0 ETH | 0.00064645 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
OptimismArbitrage
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
/*
Example contract demonstrating:
- A Balancer flash loan of a single token.
- A single-hop Uniswap V3 swap at the 0.3% fee tier (3000).
- Slippage protection via a minOut parameter.
- "onlyOwner" restriction, so an off-chain bot can submit
private transactions (e.g. Flashbots) without public front-running.
*/
import {IVault, IFlashLoanRecipient, IERC20 as BalancerIERC20} from
"@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract OptimismArbitrage is IFlashLoanRecipient, ReentrancyGuard {
using SafeERC20 for IERC20;
// Balancer's Vault and UniswapV3's Router addresses on the chain you are targeting
IVault public immutable balancerVault;
ISwapRouter public immutable uniswapV3Router;
address public owner;
// Log an event so you can monitor or debug after execution
event ArbitrageExecuted(
address indexed tokenBorrow,
uint256 amountBorrowed,
uint256 totalRepay,
uint256 amountOut,
uint256 profit
);
modifier onlyOwner() {
require(msg.sender == owner, "Not the contract owner");
_;
}
constructor(address _balancerVault, address _uniswapV3Router) {
balancerVault = IVault(_balancerVault);
uniswapV3Router = ISwapRouter(_uniswapV3Router);
owner = msg.sender;
}
/**
* @notice Initiates a flash loan from Balancer on `tokenBorrow` for `amount`.
* We'll do a single-hop swap from `tokenBorrow` → `tokenOut` on Uniswap,
* then (optionally) do something with it, or even swap back, and finally repay.
*
* @param tokenBorrow The ERC20 token to flash borrow from Balancer.
* @param amount How many tokens to borrow.
* @param tokenOut The token we want to swap into on Uniswap (single hop).
* @param minOut Slippage protection: revert if we get fewer than `minOut` out.
*
* @dev For single-hop, we're using fee = 3000 (0.3%). For multi-hop or different fee,
* you'd pass that as another parameter or do a more advanced flow.
*/
function executeFlashLoan(
address tokenBorrow,
uint256 amount,
address tokenOut,
uint256 minOut
) external onlyOwner {
// Approve Balancer to pull our borrowed token for repayment.
// Balancer needs to be able to pull 'amount' + fee from this contract later.
IERC20(tokenBorrow).safeApprove(address(balancerVault), 0);
IERC20(tokenBorrow).safeApprove(address(balancerVault), amount);
// Prepare arrays for Balancer's flashLoan function
BalancerIERC20[] memory tokens = new BalancerIERC20[](1);
tokens[0] = BalancerIERC20(tokenBorrow);
uint256[] memory amounts = new uint256[](1);
amounts[0] = amount;
// Encode data for the callback
bytes memory userData = abi.encode(tokenBorrow, amount, tokenOut, minOut);
// Initiate the flash loan
balancerVault.flashLoan(
IFlashLoanRecipient(address(this)),
tokens,
amounts,
userData
);
}
/**
* @notice Balancer calls back here after transferring us the borrowed amount.
* We must repay the flash loan (principal + fee) before returning.
*/
function receiveFlashLoan(
BalancerIERC20[] memory, // tokens
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external override nonReentrant {
require(msg.sender == address(balancerVault), "Unauthorized sender");
// Decode the data from 'executeFlashLoan'
(address tokenBorrow, uint256 amountBorrowed, address tokenOut, uint256 minOut)
= abi.decode(userData, (address, uint256, address, uint256));
uint256 fee = feeAmounts[0];
uint256 totalRepay = amountBorrowed + fee;
// We should now have `amountBorrowed` of `tokenBorrow` in this contract.
// Single-hop swap: tokenBorrow → tokenOut with 0.3% pool
uint24 poolFee = 3000; // 0.3%
uint256 amountOut = _swapExactInputSingle(
tokenBorrow,
tokenOut,
poolFee,
amountBorrowed,
minOut
);
// If your goal was purely to get more `tokenBorrow`, you would:
// - Possibly swap `tokenOut` back to `tokenBorrow` here
// so you can repay. For demonstration, let's assume
// you *also* borrowed `tokenOut` from the vault or had some `tokenBorrow`
// leftover. Another approach is to borrow the token you want to *end up with*.
// But let's assume we only borrowed one token and we must repay in that same token,
// so let's do a second swap from tokenOut -> tokenBorrow to get enough to repay.
uint256 finalBorrowBalance = _swapExactInputSingle(
tokenOut,
tokenBorrow,
poolFee,
amountOut,
1 // minimal slippage check again (in real usage, pass a real minOut param)
);
// Now we (hopefully) have enough `tokenBorrow` to repay Balancer.
require(finalBorrowBalance >= totalRepay, "Arbitrage lost money");
uint256 profit = finalBorrowBalance - totalRepay;
// Approve Balancer to pull the repayment
IERC20(tokenBorrow).safeApprove(address(balancerVault), 0);
IERC20(tokenBorrow).safeApprove(address(balancerVault), totalRepay);
// After this function finishes, Balancer will pull `totalRepay` from our contract.
// The leftover is our profit.
emit ArbitrageExecuted(tokenBorrow, amountBorrowed, totalRepay, amountOut, profit);
}
/**
* @dev Internal helper that performs a single-hop Uniswap V3 swap with the 0.3% pool.
* The `amountIn` tokens must already be in this contract.
* @param tokenIn The token we are swapping from.
* @param tokenOut The token we want to end up with.
* @param fee The fee tier (3000 = 0.3%).
* @param amountIn The amount of `tokenIn` to swap.
* @param amountOutMin Slippage check (minimum acceptable `tokenOut`).
* @return amountOut The actual amount of `tokenOut` received.
*/
function _swapExactInputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn,
uint256 amountOutMin
) internal returns (uint256 amountOut) {
if (amountIn == 0) return 0;
// Approve the Uniswap router to spend our tokenIn
IERC20(tokenIn).safeApprove(address(uniswapV3Router), 0);
IERC20(tokenIn).safeApprove(address(uniswapV3Router), amountIn);
// Construct the swap parameters
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: tokenIn,
tokenOut: tokenOut,
fee: fee,
recipient: address(this),
deadline: block.timestamp + 300, // 5-minute deadline
amountIn: amountIn,
amountOutMinimum: amountOutMin, // slippage protection
sqrtPriceLimitX96: 0 // no price limit
});
// Execute the swap
amountOut = uniswapV3Router.exactInputSingle(params);
// Reset approval (optional but considered a safety best practice)
IERC20(tokenIn).safeApprove(address(uniswapV3Router), 0);
// If amountOut < amountOutMin, Uniswap V3 will revert automatically
}
/**
* @notice Withdraw any leftover tokens (profit) to the owner.
*/
function withdrawProfits(address token, uint256 amount) external onlyOwner {
IERC20(token).safeTransfer(owner, amount);
}
/**
* @notice Update the contract owner (e.g., if you want a new bot address).
*/
function updateOwner(address newOwner) external onlyOwner {
require(newOwner != address(0), "Invalid new owner");
owner = newOwner;
}
}// 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 <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
interface IAuthentication {
/**
* @dev Returns the action identifier associated with the external function described by `selector`.
*/
function getActionId(bytes4 selector) external view returns (bytes32);
}// 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 <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev Interface for the SignatureValidator helper, used to support meta-transactions.
*/
interface ISignaturesValidator {
/**
* @dev Returns the EIP712 domain separator.
*/
function getDomainSeparator() external view returns (bytes32);
/**
* @dev Returns the next nonce used by an address to sign messages.
*/
function getNextNonce(address user) external view returns (uint256);
}// 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 <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev Interface for the TemporarilyPausable helper.
*/
interface ITemporarilyPausable {
/**
* @dev Emitted every time the pause state changes by `_setPaused`.
*/
event PausedStateChanged(bool paused);
/**
* @dev Returns the current paused state.
*/
function getPausedState()
external
view
returns (
bool paused,
uint256 pauseWindowEndTime,
uint256 bufferPeriodEndTime
);
}// 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 <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
import "../openzeppelin/IERC20.sol";
/**
* @dev Interface for WETH9.
* See https://github.com/gnosis/canonical-weth/blob/0dd1ea3e295eef916d0c6223ec63141137d22d67/contracts/WETH9.sol
*/
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// 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 <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
/**
* @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
}// 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 <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
interface IAuthorizer {
/**
* @dev Returns true if `account` can perform the action described by `actionId` in the contract `where`.
*/
function canPerform(
bytes32 actionId,
address account,
address where
) external view returns (bool);
}// 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 <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
// Inspired by Aave Protocol's IFlashLoanReceiver.
import "../solidity-utils/openzeppelin/IERC20.sol";
interface IFlashLoanRecipient {
/**
* @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
*
* At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
* call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
* Vault, or else the entire flash loan will revert.
*
* `userData` is the same value passed in the `IVault.flashLoan` call.
*/
function receiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external;
}// 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 <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
import "../solidity-utils/openzeppelin/IERC20.sol";
import "./IVault.sol";
import "./IAuthorizer.sol";
interface IProtocolFeesCollector {
event SwapFeePercentageChanged(uint256 newSwapFeePercentage);
event FlashLoanFeePercentageChanged(uint256 newFlashLoanFeePercentage);
function withdrawCollectedFees(
IERC20[] calldata tokens,
uint256[] calldata amounts,
address recipient
) external;
function setSwapFeePercentage(uint256 newSwapFeePercentage) external;
function setFlashLoanFeePercentage(uint256 newFlashLoanFeePercentage) external;
function getSwapFeePercentage() external view returns (uint256);
function getFlashLoanFeePercentage() external view returns (uint256);
function getCollectedFeeAmounts(IERC20[] memory tokens) external view returns (uint256[] memory feeAmounts);
function getAuthorizer() external view returns (IAuthorizer);
function vault() external view returns (IVault);
}// 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 <http://www.gnu.org/licenses/>.
pragma experimental ABIEncoderV2;
import "../solidity-utils/openzeppelin/IERC20.sol";
import "../solidity-utils/helpers/IAuthentication.sol";
import "../solidity-utils/helpers/ISignaturesValidator.sol";
import "../solidity-utils/helpers/ITemporarilyPausable.sol";
import "../solidity-utils/misc/IWETH.sol";
import "./IAsset.sol";
import "./IAuthorizer.sol";
import "./IFlashLoanRecipient.sol";
import "./IProtocolFeesCollector.sol";
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev Full external interface for the Vault core contract - no external or public methods exist in the contract that
* don't override one of these declarations.
*/
interface IVault is ISignaturesValidator, ITemporarilyPausable, IAuthentication {
// Generalities about the Vault:
//
// - Whenever documentation refers to 'tokens', it strictly refers to ERC20-compliant token contracts. Tokens are
// transferred out of the Vault by calling the `IERC20.transfer` function, and transferred in by calling
// `IERC20.transferFrom`. In these cases, the sender must have previously allowed the Vault to use their tokens by
// calling `IERC20.approve`. The only deviation from the ERC20 standard that is supported is functions not returning
// a boolean value: in these scenarios, a non-reverting call is assumed to be successful.
//
// - All non-view functions in the Vault are non-reentrant: calling them while another one is mid-execution (e.g.
// while execution control is transferred to a token contract during a swap) will result in a revert. View
// functions can be called in a re-reentrant way, but doing so might cause them to return inconsistent results.
// Contracts calling view functions in the Vault must make sure the Vault has not already been entered.
//
// - View functions revert if referring to either unregistered Pools, or unregistered tokens for registered Pools.
// Authorizer
//
// Some system actions are permissioned, like setting and collecting protocol fees. This permissioning system exists
// outside of the Vault in the Authorizer contract: the Vault simply calls the Authorizer to check if the caller
// can perform a given action.
/**
* @dev Returns the Vault's Authorizer.
*/
function getAuthorizer() external view returns (IAuthorizer);
/**
* @dev Sets a new Authorizer for the Vault. The caller must be allowed by the current Authorizer to do this.
*
* Emits an `AuthorizerChanged` event.
*/
function setAuthorizer(IAuthorizer newAuthorizer) external;
/**
* @dev Emitted when a new authorizer is set by `setAuthorizer`.
*/
event AuthorizerChanged(IAuthorizer indexed newAuthorizer);
// Relayers
//
// Additionally, it is possible for an account to perform certain actions on behalf of another one, using their
// Vault ERC20 allowance and Internal Balance. These accounts are said to be 'relayers' for these Vault functions,
// and are expected to be smart contracts with sound authentication mechanisms. For an account to be able to wield
// this power, two things must occur:
// - The Authorizer must grant the account the permission to be a relayer for the relevant Vault function. This
// means that Balancer governance must approve each individual contract to act as a relayer for the intended
// functions.
// - Each user must approve the relayer to act on their behalf.
// This double protection means users cannot be tricked into approving malicious relayers (because they will not
// have been allowed by the Authorizer via governance), nor can malicious relayers approved by a compromised
// Authorizer or governance drain user funds, since they would also need to be approved by each individual user.
/**
* @dev Returns true if `user` has approved `relayer` to act as a relayer for them.
*/
function hasApprovedRelayer(address user, address relayer) external view returns (bool);
/**
* @dev Allows `relayer` to act as a relayer for `sender` if `approved` is true, and disallows it otherwise.
*
* Emits a `RelayerApprovalChanged` event.
*/
function setRelayerApproval(
address sender,
address relayer,
bool approved
) external;
/**
* @dev Emitted every time a relayer is approved or disapproved by `setRelayerApproval`.
*/
event RelayerApprovalChanged(address indexed relayer, address indexed sender, bool approved);
// 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 Returns `user`'s Internal Balance for a set of tokens.
*/
function getInternalBalance(address user, IERC20[] memory tokens) external view returns (uint256[] memory);
/**
* @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;
IAsset 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 }
/**
* @dev Emitted when a user's Internal Balance changes, either from calls to `manageUserBalance`, or through
* interacting with Pools using Internal Balance.
*
* Because Internal Balance works exclusively with ERC20 tokens, ETH deposits and withdrawals will use the WETH
* address.
*/
event InternalBalanceChanged(address indexed user, IERC20 indexed token, int256 delta);
/**
* @dev Emitted when a user's Vault ERC20 allowance is used by the Vault to transfer tokens to an external account.
*/
event ExternalBalanceTransfer(IERC20 indexed token, address indexed sender, address recipient, uint256 amount);
// Pools
//
// There are three specialization settings for Pools, which allow for cheaper swaps at the cost of reduced
// functionality:
//
// - General: no specialization, suited for all Pools. IGeneralPool is used for swap request callbacks, passing the
// balance of all tokens in the Pool. These Pools have the largest swap costs (because of the extra storage reads),
// which increase with the number of registered tokens.
//
// - Minimal Swap Info: IMinimalSwapInfoPool is used instead of IGeneralPool, which saves gas by only passing the
// balance of the two tokens involved in the swap. This is suitable for some pricing algorithms, like the weighted
// constant product one popularized by Balancer V1. Swap costs are smaller compared to general Pools, and are
// independent of the number of registered tokens.
//
// - Two Token: only allows two tokens to be registered. This achieves the lowest possible swap gas cost. Like
// minimal swap info Pools, these are called via IMinimalSwapInfoPool.
enum PoolSpecialization { GENERAL, MINIMAL_SWAP_INFO, TWO_TOKEN }
/**
* @dev Registers the caller account as a Pool with a given specialization setting. Returns the Pool's ID, which
* is used in all Pool-related functions. Pools cannot be deregistered, nor can the Pool's specialization be
* changed.
*
* The caller is expected to be a smart contract that implements either `IGeneralPool` or `IMinimalSwapInfoPool`,
* depending on the chosen specialization setting. This contract is known as the Pool's contract.
*
* Note that the same contract may register itself as multiple Pools with unique Pool IDs, or in other words,
* multiple Pools may share the same contract.
*
* Emits a `PoolRegistered` event.
*/
function registerPool(PoolSpecialization specialization) external returns (bytes32);
/**
* @dev Emitted when a Pool is registered by calling `registerPool`.
*/
event PoolRegistered(bytes32 indexed poolId, address indexed poolAddress, PoolSpecialization specialization);
/**
* @dev Returns a Pool's contract address and specialization setting.
*/
function getPool(bytes32 poolId) external view returns (address, PoolSpecialization);
/**
* @dev Registers `tokens` for the `poolId` Pool. Must be called by the Pool's contract.
*
* Pools can only interact with tokens they have registered. Users join a Pool by transferring registered tokens,
* exit by receiving registered tokens, and can only swap registered tokens.
*
* Each token can only be registered once. For Pools with the Two Token specialization, `tokens` must have a length
* of two, that is, both tokens must be registered in the same `registerTokens` call, and they must be sorted in
* ascending order.
*
* The `tokens` and `assetManagers` arrays must have the same length, and each entry in these indicates the Asset
* Manager for the corresponding token. Asset Managers can manage a Pool's tokens via `managePoolBalance`,
* depositing and withdrawing them directly, and can even set their balance to arbitrary amounts. They are therefore
* expected to be highly secured smart contracts with sound design principles, and the decision to register an
* Asset Manager should not be made lightly.
*
* Pools can choose not to assign an Asset Manager to a given token by passing in the zero address. Once an Asset
* Manager is set, it cannot be changed except by deregistering the associated token and registering again with a
* different Asset Manager.
*
* Emits a `TokensRegistered` event.
*/
function registerTokens(
bytes32 poolId,
IERC20[] memory tokens,
address[] memory assetManagers
) external;
/**
* @dev Emitted when a Pool registers tokens by calling `registerTokens`.
*/
event TokensRegistered(bytes32 indexed poolId, IERC20[] tokens, address[] assetManagers);
/**
* @dev Deregisters `tokens` for the `poolId` Pool. Must be called by the Pool's contract.
*
* Only registered tokens (via `registerTokens`) can be deregistered. Additionally, they must have zero total
* balance. For Pools with the Two Token specialization, `tokens` must have a length of two, that is, both tokens
* must be deregistered in the same `deregisterTokens` call.
*
* A deregistered token can be re-registered later on, possibly with a different Asset Manager.
*
* Emits a `TokensDeregistered` event.
*/
function deregisterTokens(bytes32 poolId, IERC20[] memory tokens) external;
/**
* @dev Emitted when a Pool deregisters tokens by calling `deregisterTokens`.
*/
event TokensDeregistered(bytes32 indexed poolId, IERC20[] tokens);
/**
* @dev Returns detailed information for a Pool's registered token.
*
* `cash` is the number of tokens the Vault currently holds for the Pool. `managed` is the number of tokens
* withdrawn and held outside the Vault by the Pool's token Asset Manager. The Pool's total balance for `token`
* equals the sum of `cash` and `managed`.
*
* Internally, `cash` and `managed` are stored using 112 bits. No action can ever cause a Pool's token `cash`,
* `managed` or `total` balance to be greater than 2^112 - 1.
*
* `lastChangeBlock` is the number of the block in which `token`'s total balance was last modified (via either a
* join, exit, swap, or Asset Manager update). This value is useful to avoid so-called 'sandwich attacks', for
* example when developing price oracles. A change of zero (e.g. caused by a swap with amount zero) is considered a
* change for this purpose, and will update `lastChangeBlock`.
*
* `assetManager` is the Pool's token Asset Manager.
*/
function getPoolTokenInfo(bytes32 poolId, IERC20 token)
external
view
returns (
uint256 cash,
uint256 managed,
uint256 lastChangeBlock,
address assetManager
);
/**
* @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of
* the tokens' `balances` changed.
*
* The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all
* Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.
*
* If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same
* order as passed to `registerTokens`.
*
* Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are
* the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`
* instead.
*/
function getPoolTokens(bytes32 poolId)
external
view
returns (
IERC20[] memory tokens,
uint256[] memory balances,
uint256 lastChangeBlock
);
/**
* @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will
* trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized
* Pool shares.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount
* to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces
* these maximums.
*
* If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. 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 not possible to combine ETH and WETH in the same join. Any excess ETH will be sent
* back to the caller (not the sender, which is important for relayers).
*
* `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when
* interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be
* sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final
* `assets` array might not be sorted. Pools with no registered tokens cannot be joined.
*
* If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only
* be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be
* withdrawn from Internal Balance: attempting to do so will trigger a revert.
*
* This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement
* their own custom logic. This typically requires additional information from the user (such as the expected number
* of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed
* directly to the Pool's contract, as is `recipient`.
*
* Emits a `PoolBalanceChanged` event.
*/
function joinPool(
bytes32 poolId,
address sender,
address recipient,
JoinPoolRequest memory request
) external payable;
struct JoinPoolRequest {
IAsset[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
/**
* @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will
* trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized
* Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see
* `getPoolTokenInfo`).
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum
* token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:
* it just enforces these minimums.
*
* If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the 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 not possible to combine ETH and WETH in the same exit.
*
* `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when
* interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must
* be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the
* final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.
*
* If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,
* an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to
* do so will trigger a revert.
*
* `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the
* `tokens` array. This array must match the Pool's registered tokens.
*
* This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement
* their own custom logic. This typically requires additional information from the user (such as the expected number
* of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and
* passed directly to the Pool's contract.
*
* Emits a `PoolBalanceChanged` event.
*/
function exitPool(
bytes32 poolId,
address sender,
address payable recipient,
ExitPoolRequest memory request
) external;
struct ExitPoolRequest {
IAsset[] assets;
uint256[] minAmountsOut;
bytes userData;
bool toInternalBalance;
}
/**
* @dev Emitted when a user joins or exits a Pool by calling `joinPool` or `exitPool`, respectively.
*/
event PoolBalanceChanged(
bytes32 indexed poolId,
address indexed liquidityProvider,
IERC20[] tokens,
int256[] deltas,
uint256[] protocolFeeAmounts
);
enum PoolBalanceChangeKind { JOIN, EXIT }
// 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;
IAsset assetIn;
IAsset 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,
IAsset[] 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 Emitted for each individual swap performed by `swap` or `batchSwap`.
*/
event Swap(
bytes32 indexed poolId,
IERC20 indexed tokenIn,
IERC20 indexed tokenOut,
uint256 amountIn,
uint256 amountOut
);
/**
* @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;
}
/**
* @dev Simulates a call to `batchSwap`, returning an array of Vault asset deltas. Calls to `swap` cannot be
* simulated directly, but an equivalent `batchSwap` call can and will yield the exact same result.
*
* Each element in the array corresponds to the asset at the same index, and indicates the number of tokens (or ETH)
* the Vault would take from the sender (if positive) or send to the recipient (if negative). The arguments it
* receives are the same that an equivalent `batchSwap` call would receive.
*
* Unlike `batchSwap`, this function performs no checks on the sender or recipient field in the `funds` struct.
* This makes it suitable to be called by off-chain applications via eth_call without needing to hold tokens,
* approve them for the Vault, or even know a user's address.
*
* Note that this function is not 'view' (due to implementation details): the client code must explicitly execute
* eth_call instead of eth_sendTransaction.
*/
function queryBatchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
IAsset[] memory assets,
FundManagement memory funds
) external returns (int256[] memory assetDeltas);
// Flash Loans
/**
* @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it,
* and then reverting unless the tokens plus a proportional protocol fee have been returned.
*
* The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount
* for each token contract. `tokens` must be sorted in ascending order.
*
* The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the
* `receiveFlashLoan` call.
*
* Emits `FlashLoan` events.
*/
function flashLoan(
IFlashLoanRecipient recipient,
IERC20[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external;
/**
* @dev Emitted for each individual flash loan performed by `flashLoan`.
*/
event FlashLoan(IFlashLoanRecipient indexed recipient, IERC20 indexed token, uint256 amount, uint256 feeAmount);
// Asset Management
//
// Each token registered for a Pool can be assigned an Asset Manager, which is able to freely withdraw the Pool's
// tokens from the Vault, deposit them, or assign arbitrary values to its `managed` balance (see
// `getPoolTokenInfo`). This makes them extremely powerful and dangerous. Even if an Asset Manager only directly
// controls one of the tokens in a Pool, a malicious manager could set that token's balance to manipulate the
// prices of the other tokens, and then drain the Pool with swaps. The risk of using Asset Managers is therefore
// not constrained to the tokens they are managing, but extends to the entire Pool's holdings.
//
// However, a properly designed Asset Manager smart contract can be safely used for the Pool's benefit,
// for example by lending unused tokens out for interest, or using them to participate in voting protocols.
//
// This concept is unrelated to the IAsset interface.
/**
* @dev Performs a set of Pool balance operations, which may be either withdrawals, deposits or updates.
*
* Pool Balance management features batching, which means a single contract call can be used to perform multiple
* operations of different kinds, with different Pools and tokens, at once.
*
* For each operation, the caller must be registered as the Asset Manager for `token` in `poolId`.
*/
function managePoolBalance(PoolBalanceOp[] memory ops) external;
struct PoolBalanceOp {
PoolBalanceOpKind kind;
bytes32 poolId;
IERC20 token;
uint256 amount;
}
/**
* Withdrawals decrease the Pool's cash, but increase its managed balance, leaving the total balance unchanged.
*
* Deposits increase the Pool's cash, but decrease its managed balance, leaving the total balance unchanged.
*
* Updates don't affect the Pool's cash balance, but because the managed balance changes, it does alter the total.
* The external amount can be either increased or decreased by this call (i.e., reporting a gain or a loss).
*/
enum PoolBalanceOpKind { WITHDRAW, DEPOSIT, UPDATE }
/**
* @dev Emitted when a Pool's token Asset Manager alters its balance via `managePoolBalance`.
*/
event PoolBalanceManaged(
bytes32 indexed poolId,
address indexed assetManager,
IERC20 indexed token,
int256 cashDelta,
int256 managedDelta
);
// Protocol Fees
//
// Some operations cause the Vault to collect tokens in the form of protocol fees, which can then be withdrawn by
// permissioned accounts.
//
// There are two kinds of protocol fees:
//
// - flash loan fees: charged on all flash loans, as a percentage of the amounts lent.
//
// - swap fees: a percentage of the fees charged by Pools when performing swaps. For a number of reasons, including
// swap gas costs and interface simplicity, protocol swap fees are not charged on each individual swap. Rather,
// Pools are expected to keep track of how much they have charged in swap fees, and pay any outstanding debts to the
// Vault when they are joined or exited. This prevents users from joining a Pool with unpaid debt, as well as
// exiting a Pool in debt without first paying their share.
/**
* @dev Returns the current protocol fee module.
*/
function getProtocolFeesCollector() external view returns (IProtocolFeesCollector);
/**
* @dev Safety mechanism to pause most Vault operations in the event of an emergency - typically detection of an
* error in some part of the system.
*
* The Vault can only be paused during an initial time period, after which pausing is forever disabled.
*
* While the contract is paused, the following features are disabled:
* - depositing and transferring internal balance
* - transferring external balance (using the Vault's allowance)
* - swaps
* - joining Pools
* - Asset Manager interactions
*
* Internal Balance can still be withdrawn, and Pools exited.
*/
function setPaused(bool paused) external;
/**
* @dev Returns the Vault's WETH instance.
*/
function WETH() external view returns (IWETH);
// solhint-disable-previous-line func-name-mixedcase
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
/// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol';
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}{
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_balancerVault","type":"address"},{"internalType":"address","name":"_uniswapV3Router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenBorrow","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountBorrowed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalRepay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"}],"name":"ArbitrageExecuted","type":"event"},{"inputs":[],"name":"balancerVault","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenBorrow","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minOut","type":"uint256"}],"name":"executeFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"feeAmounts","type":"uint256[]"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"receiveFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV3Router","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"updateOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawProfits","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b50604051620024533803806200245383398181016040528101906200003791906200015a565b60016000819055508173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff168152505033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050620001a1565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200012282620000f5565b9050919050565b620001348162000115565b81146200014057600080fd5b50565b600081519050620001548162000129565b92915050565b60008060408385031215620001745762000173620000f0565b5b6000620001848582860162000143565b9250506020620001978582860162000143565b9150509250929050565b60805160a0516122466200020d6000396000818161017201528181610a2901528181610a7501528181610b660152610c0701526000818161014e015281816103e80152818161054801528181610594015281816106db0152818161072701526108a501526122466000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80638da5cb5b1161005b5780638da5cb5b146100da578063aafc9651146100f8578063f04f270714610114578063f9f41638146101305761007d565b8063158274a5146100825780632c76d7a6146100a0578063880cdc31146100be575b600080fd5b61008a61014c565b60405161009791906110c6565b60405180910390f35b6100a8610170565b6040516100b59190611102565b60405180910390f35b6100d860048036038101906100d3919061116f565b610194565b005b6100e26102d7565b6040516100ef91906111ab565b60405180910390f35b610112600480360381019061010d91906111fc565b6102fd565b005b61012e6004803603810190610129919061154b565b6103de565b005b61014a60048036038101906101459190611622565b610646565b005b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610224576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161021b906116e6565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610293576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161028a90611752565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461038d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610384906116e6565b60405180910390fd5b6103da600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff1661093d9092919063ffffffff16565b5050565b6103e66109c3565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610474576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161046b906117be565b60405180910390fd5b6000806000808480602001905181019061048e9190611831565b93509350935093506000866000815181106104ac576104ab611898565b5b60200260200101519050600081856104c491906118f6565b90506000610bb8905060006104dc8887848a89610a12565b905060006104ee878a85856001610a12565b905083811015610533576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052a90611976565b60405180910390fd5b600084826105419190611996565b905061058f7f000000000000000000000000000000000000000000000000000000000000000060008c73ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b6105da7f0000000000000000000000000000000000000000000000000000000000000000868c73ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b8973ffffffffffffffffffffffffffffffffffffffff167f635ba3250f563c26a1442217170c38a03b0a7ce671b624cfcbe68e8e9a69e5c88a87868560405161062694939291906119d9565b60405180910390a250505050505050505050610640610da8565b50505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106cd906116e6565b60405180910390fd5b6107227f000000000000000000000000000000000000000000000000000000000000000060008673ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b61076d7f0000000000000000000000000000000000000000000000000000000000000000848673ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b6000600167ffffffffffffffff81111561078a57610789611252565b5b6040519080825280602002602001820160405280156107b85781602001602082028036833780820191505090505b50905084816000815181106107d0576107cf611898565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600167ffffffffffffffff81111561082757610826611252565b5b6040519080825280602002602001820160405280156108555781602001602082028036833780820191505090505b509050848160008151811061086d5761086c611898565b5b6020026020010181815250506000868686866040516020016108929493929190611a1e565b60405160208183030381529060405290507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635c38449e308585856040518563ffffffff1660e01b81526004016109029493929190611c91565b600060405180830381600087803b15801561091c57600080fd5b505af1158015610930573d6000803e3d6000fd5b5050505050505050505050565b6109be8363a9059cbb60e01b848460405160240161095c929190611ceb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610db2565b505050565b600260005403610a08576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ff90611d60565b60405180910390fd5b6002600081905550565b6000808303610a245760009050610c50565b610a707f000000000000000000000000000000000000000000000000000000000000000060008873ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b610abb7f0000000000000000000000000000000000000000000000000000000000000000848873ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b60006040518061010001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018662ffffff1681526020013073ffffffffffffffffffffffffffffffffffffffff16815260200161012c42610b3691906118f6565b8152602001858152602001848152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663414bf389826040518263ffffffff1660e01b8152600401610bbd9190611e5e565b6020604051808303816000875af1158015610bdc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c009190611e7a565b9150610c4e7f000000000000000000000000000000000000000000000000000000000000000060008973ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b505b95945050505050565b6000811480610ce3575060008373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401610ca0929190611ea7565b602060405180830381865afa158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce19190611e7a565b145b610d22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d1990611f42565b60405180910390fd5b610da38363095ea7b360e01b8484604051602401610d41929190611ceb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610db2565b505050565b6001600081905550565b6000610e14826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610e7a9092919063ffffffff16565b9050600081511480610e36575080806020019051810190610e359190611f9a565b5b610e75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6c90612039565b60405180910390fd5b505050565b6060610e898484600085610e92565b90509392505050565b606082471015610ed7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ece906120cb565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610f009190612127565b60006040518083038185875af1925050503d8060008114610f3d576040519150601f19603f3d011682016040523d82523d6000602084013e610f42565b606091505b5091509150610f5387838387610f5f565b92505050949350505050565b60608315610fc1576000835103610fb957610f7985610fd4565b610fb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610faf9061218a565b60405180910390fd5b5b829050610fcc565b610fcb8383610ff7565b5b949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60008251111561100a5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161103e91906121ee565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061108c61108761108284611047565b611067565b611047565b9050919050565b600061109e82611071565b9050919050565b60006110b082611093565b9050919050565b6110c0816110a5565b82525050565b60006020820190506110db60008301846110b7565b92915050565b60006110ec82611093565b9050919050565b6110fc816110e1565b82525050565b600060208201905061111760008301846110f3565b92915050565b6000604051905090565b600080fd5b600080fd5b600061113c82611047565b9050919050565b61114c81611131565b811461115757600080fd5b50565b60008135905061116981611143565b92915050565b60006020828403121561118557611184611127565b5b60006111938482850161115a565b91505092915050565b6111a581611131565b82525050565b60006020820190506111c0600083018461119c565b92915050565b6000819050919050565b6111d9816111c6565b81146111e457600080fd5b50565b6000813590506111f6816111d0565b92915050565b6000806040838503121561121357611212611127565b5b60006112218582860161115a565b9250506020611232858286016111e7565b9150509250929050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61128a82611241565b810181811067ffffffffffffffff821117156112a9576112a8611252565b5b80604052505050565b60006112bc61111d565b90506112c88282611281565b919050565b600067ffffffffffffffff8211156112e8576112e7611252565b5b602082029050602081019050919050565b600080fd5b600061130982611131565b9050919050565b611319816112fe565b811461132457600080fd5b50565b60008135905061133681611310565b92915050565b600061134f61134a846112cd565b6112b2565b90508083825260208201905060208402830185811115611372576113716112f9565b5b835b8181101561139b57806113878882611327565b845260208401935050602081019050611374565b5050509392505050565b600082601f8301126113ba576113b961123c565b5b81356113ca84826020860161133c565b91505092915050565b600067ffffffffffffffff8211156113ee576113ed611252565b5b602082029050602081019050919050565b600061141261140d846113d3565b6112b2565b90508083825260208201905060208402830185811115611435576114346112f9565b5b835b8181101561145e578061144a88826111e7565b845260208401935050602081019050611437565b5050509392505050565b600082601f83011261147d5761147c61123c565b5b813561148d8482602086016113ff565b91505092915050565b600080fd5b600067ffffffffffffffff8211156114b6576114b5611252565b5b6114bf82611241565b9050602081019050919050565b82818337600083830152505050565b60006114ee6114e98461149b565b6112b2565b90508281526020810184848401111561150a57611509611496565b5b6115158482856114cc565b509392505050565b600082601f8301126115325761153161123c565b5b81356115428482602086016114db565b91505092915050565b6000806000806080858703121561156557611564611127565b5b600085013567ffffffffffffffff8111156115835761158261112c565b5b61158f878288016113a5565b945050602085013567ffffffffffffffff8111156115b0576115af61112c565b5b6115bc87828801611468565b935050604085013567ffffffffffffffff8111156115dd576115dc61112c565b5b6115e987828801611468565b925050606085013567ffffffffffffffff81111561160a5761160961112c565b5b6116168782880161151d565b91505092959194509250565b6000806000806080858703121561163c5761163b611127565b5b600061164a8782880161115a565b945050602061165b878288016111e7565b935050604061166c8782880161115a565b925050606061167d878288016111e7565b91505092959194509250565b600082825260208201905092915050565b7f4e6f742074686520636f6e7472616374206f776e657200000000000000000000600082015250565b60006116d0601683611689565b91506116db8261169a565b602082019050919050565b600060208201905081810360008301526116ff816116c3565b9050919050565b7f496e76616c6964206e6577206f776e6572000000000000000000000000000000600082015250565b600061173c601183611689565b915061174782611706565b602082019050919050565b6000602082019050818103600083015261176b8161172f565b9050919050565b7f556e617574686f72697a65642073656e64657200000000000000000000000000600082015250565b60006117a8601383611689565b91506117b382611772565b602082019050919050565b600060208201905081810360008301526117d78161179b565b9050919050565b60006117e982611047565b9050919050565b6117f9816117de565b811461180457600080fd5b50565b600081519050611816816117f0565b92915050565b60008151905061182b816111d0565b92915050565b6000806000806080858703121561184b5761184a611127565b5b600061185987828801611807565b945050602061186a8782880161181c565b935050604061187b87828801611807565b925050606061188c8782880161181c565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611901826111c6565b915061190c836111c6565b9250828201905080821115611924576119236118c7565b5b92915050565b7f417262697472616765206c6f7374206d6f6e6579000000000000000000000000600082015250565b6000611960601483611689565b915061196b8261192a565b602082019050919050565b6000602082019050818103600083015261198f81611953565b9050919050565b60006119a1826111c6565b91506119ac836111c6565b92508282039050818111156119c4576119c36118c7565b5b92915050565b6119d3816111c6565b82525050565b60006080820190506119ee60008301876119ca565b6119fb60208301866119ca565b611a0860408301856119ca565b611a1560608301846119ca565b95945050505050565b6000608082019050611a33600083018761119c565b611a4060208301866119ca565b611a4d604083018561119c565b611a5a60608301846119ca565b95945050505050565b6000611a6e82611093565b9050919050565b611a7e81611a63565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000611abb82611093565b9050919050565b611acb81611ab0565b82525050565b6000611add8383611ac2565b60208301905092915050565b6000602082019050919050565b6000611b0182611a84565b611b0b8185611a8f565b9350611b1683611aa0565b8060005b83811015611b47578151611b2e8882611ad1565b9750611b3983611ae9565b925050600181019050611b1a565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b611b89816111c6565b82525050565b6000611b9b8383611b80565b60208301905092915050565b6000602082019050919050565b6000611bbf82611b54565b611bc98185611b5f565b9350611bd483611b70565b8060005b83811015611c05578151611bec8882611b8f565b9750611bf783611ba7565b925050600181019050611bd8565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611c4c578082015181840152602081019050611c31565b60008484015250505050565b6000611c6382611c12565b611c6d8185611c1d565b9350611c7d818560208601611c2e565b611c8681611241565b840191505092915050565b6000608082019050611ca66000830187611a75565b8181036020830152611cb88186611af6565b90508181036040830152611ccc8185611bb4565b90508181036060830152611ce08184611c58565b905095945050505050565b6000604082019050611d00600083018561119c565b611d0d60208301846119ca565b9392505050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000611d4a601f83611689565b9150611d5582611d14565b602082019050919050565b60006020820190508181036000830152611d7981611d3d565b9050919050565b611d8981611131565b82525050565b600062ffffff82169050919050565b611da781611d8f565b82525050565b611db681611047565b82525050565b61010082016000820151611dd36000850182611d80565b506020820151611de66020850182611d80565b506040820151611df96040850182611d9e565b506060820151611e0c6060850182611d80565b506080820151611e1f6080850182611b80565b5060a0820151611e3260a0850182611b80565b5060c0820151611e4560c0850182611b80565b5060e0820151611e5860e0850182611dad565b50505050565b600061010082019050611e746000830184611dbc565b92915050565b600060208284031215611e9057611e8f611127565b5b6000611e9e8482850161181c565b91505092915050565b6000604082019050611ebc600083018561119c565b611ec9602083018461119c565b9392505050565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60008201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000602082015250565b6000611f2c603683611689565b9150611f3782611ed0565b604082019050919050565b60006020820190508181036000830152611f5b81611f1f565b9050919050565b60008115159050919050565b611f7781611f62565b8114611f8257600080fd5b50565b600081519050611f9481611f6e565b92915050565b600060208284031215611fb057611faf611127565b5b6000611fbe84828501611f85565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b6000612023602a83611689565b915061202e82611fc7565b604082019050919050565b6000602082019050818103600083015261205281612016565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b60006120b5602683611689565b91506120c082612059565b604082019050919050565b600060208201905081810360008301526120e4816120a8565b9050919050565b600081905092915050565b600061210182611c12565b61210b81856120eb565b935061211b818560208601611c2e565b80840191505092915050565b600061213382846120f6565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000612174601d83611689565b915061217f8261213e565b602082019050919050565b600060208201905081810360008301526121a381612167565b9050919050565b600081519050919050565b60006121c0826121aa565b6121ca8185611689565b93506121da818560208601611c2e565b6121e381611241565b840191505092915050565b6000602082019050818103600083015261220881846121b5565b90509291505056fea264697066735822122001e794ca984693dc7fc1fbc81adccb70886c1db28660dcad0191b31c2875a54c64736f6c63430008120033000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061007d5760003560e01c80638da5cb5b1161005b5780638da5cb5b146100da578063aafc9651146100f8578063f04f270714610114578063f9f41638146101305761007d565b8063158274a5146100825780632c76d7a6146100a0578063880cdc31146100be575b600080fd5b61008a61014c565b60405161009791906110c6565b60405180910390f35b6100a8610170565b6040516100b59190611102565b60405180910390f35b6100d860048036038101906100d3919061116f565b610194565b005b6100e26102d7565b6040516100ef91906111ab565b60405180910390f35b610112600480360381019061010d91906111fc565b6102fd565b005b61012e6004803603810190610129919061154b565b6103de565b005b61014a60048036038101906101459190611622565b610646565b005b7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c881565b7f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156481565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610224576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161021b906116e6565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610293576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161028a90611752565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461038d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610384906116e6565b60405180910390fd5b6103da600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff1661093d9092919063ffffffff16565b5050565b6103e66109c3565b7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c873ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610474576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161046b906117be565b60405180910390fd5b6000806000808480602001905181019061048e9190611831565b93509350935093506000866000815181106104ac576104ab611898565b5b60200260200101519050600081856104c491906118f6565b90506000610bb8905060006104dc8887848a89610a12565b905060006104ee878a85856001610a12565b905083811015610533576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052a90611976565b60405180910390fd5b600084826105419190611996565b905061058f7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c860008c73ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b6105da7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8868c73ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b8973ffffffffffffffffffffffffffffffffffffffff167f635ba3250f563c26a1442217170c38a03b0a7ce671b624cfcbe68e8e9a69e5c88a87868560405161062694939291906119d9565b60405180910390a250505050505050505050610640610da8565b50505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106cd906116e6565b60405180910390fd5b6107227f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c860008673ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b61076d7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8848673ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b6000600167ffffffffffffffff81111561078a57610789611252565b5b6040519080825280602002602001820160405280156107b85781602001602082028036833780820191505090505b50905084816000815181106107d0576107cf611898565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600167ffffffffffffffff81111561082757610826611252565b5b6040519080825280602002602001820160405280156108555781602001602082028036833780820191505090505b509050848160008151811061086d5761086c611898565b5b6020026020010181815250506000868686866040516020016108929493929190611a1e565b60405160208183030381529060405290507f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c873ffffffffffffffffffffffffffffffffffffffff16635c38449e308585856040518563ffffffff1660e01b81526004016109029493929190611c91565b600060405180830381600087803b15801561091c57600080fd5b505af1158015610930573d6000803e3d6000fd5b5050505050505050505050565b6109be8363a9059cbb60e01b848460405160240161095c929190611ceb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610db2565b505050565b600260005403610a08576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ff90611d60565b60405180910390fd5b6002600081905550565b6000808303610a245760009050610c50565b610a707f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156460008873ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b610abb7f000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564848873ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b60006040518061010001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018662ffffff1681526020013073ffffffffffffffffffffffffffffffffffffffff16815260200161012c42610b3691906118f6565b8152602001858152602001848152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090507f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156473ffffffffffffffffffffffffffffffffffffffff1663414bf389826040518263ffffffff1660e01b8152600401610bbd9190611e5e565b6020604051808303816000875af1158015610bdc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c009190611e7a565b9150610c4e7f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156460008973ffffffffffffffffffffffffffffffffffffffff16610c599092919063ffffffff16565b505b95945050505050565b6000811480610ce3575060008373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401610ca0929190611ea7565b602060405180830381865afa158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce19190611e7a565b145b610d22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d1990611f42565b60405180910390fd5b610da38363095ea7b360e01b8484604051602401610d41929190611ceb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610db2565b505050565b6001600081905550565b6000610e14826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610e7a9092919063ffffffff16565b9050600081511480610e36575080806020019051810190610e359190611f9a565b5b610e75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6c90612039565b60405180910390fd5b505050565b6060610e898484600085610e92565b90509392505050565b606082471015610ed7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ece906120cb565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610f009190612127565b60006040518083038185875af1925050503d8060008114610f3d576040519150601f19603f3d011682016040523d82523d6000602084013e610f42565b606091505b5091509150610f5387838387610f5f565b92505050949350505050565b60608315610fc1576000835103610fb957610f7985610fd4565b610fb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610faf9061218a565b60405180910390fd5b5b829050610fcc565b610fcb8383610ff7565b5b949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60008251111561100a5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161103e91906121ee565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061108c61108761108284611047565b611067565b611047565b9050919050565b600061109e82611071565b9050919050565b60006110b082611093565b9050919050565b6110c0816110a5565b82525050565b60006020820190506110db60008301846110b7565b92915050565b60006110ec82611093565b9050919050565b6110fc816110e1565b82525050565b600060208201905061111760008301846110f3565b92915050565b6000604051905090565b600080fd5b600080fd5b600061113c82611047565b9050919050565b61114c81611131565b811461115757600080fd5b50565b60008135905061116981611143565b92915050565b60006020828403121561118557611184611127565b5b60006111938482850161115a565b91505092915050565b6111a581611131565b82525050565b60006020820190506111c0600083018461119c565b92915050565b6000819050919050565b6111d9816111c6565b81146111e457600080fd5b50565b6000813590506111f6816111d0565b92915050565b6000806040838503121561121357611212611127565b5b60006112218582860161115a565b9250506020611232858286016111e7565b9150509250929050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61128a82611241565b810181811067ffffffffffffffff821117156112a9576112a8611252565b5b80604052505050565b60006112bc61111d565b90506112c88282611281565b919050565b600067ffffffffffffffff8211156112e8576112e7611252565b5b602082029050602081019050919050565b600080fd5b600061130982611131565b9050919050565b611319816112fe565b811461132457600080fd5b50565b60008135905061133681611310565b92915050565b600061134f61134a846112cd565b6112b2565b90508083825260208201905060208402830185811115611372576113716112f9565b5b835b8181101561139b57806113878882611327565b845260208401935050602081019050611374565b5050509392505050565b600082601f8301126113ba576113b961123c565b5b81356113ca84826020860161133c565b91505092915050565b600067ffffffffffffffff8211156113ee576113ed611252565b5b602082029050602081019050919050565b600061141261140d846113d3565b6112b2565b90508083825260208201905060208402830185811115611435576114346112f9565b5b835b8181101561145e578061144a88826111e7565b845260208401935050602081019050611437565b5050509392505050565b600082601f83011261147d5761147c61123c565b5b813561148d8482602086016113ff565b91505092915050565b600080fd5b600067ffffffffffffffff8211156114b6576114b5611252565b5b6114bf82611241565b9050602081019050919050565b82818337600083830152505050565b60006114ee6114e98461149b565b6112b2565b90508281526020810184848401111561150a57611509611496565b5b6115158482856114cc565b509392505050565b600082601f8301126115325761153161123c565b5b81356115428482602086016114db565b91505092915050565b6000806000806080858703121561156557611564611127565b5b600085013567ffffffffffffffff8111156115835761158261112c565b5b61158f878288016113a5565b945050602085013567ffffffffffffffff8111156115b0576115af61112c565b5b6115bc87828801611468565b935050604085013567ffffffffffffffff8111156115dd576115dc61112c565b5b6115e987828801611468565b925050606085013567ffffffffffffffff81111561160a5761160961112c565b5b6116168782880161151d565b91505092959194509250565b6000806000806080858703121561163c5761163b611127565b5b600061164a8782880161115a565b945050602061165b878288016111e7565b935050604061166c8782880161115a565b925050606061167d878288016111e7565b91505092959194509250565b600082825260208201905092915050565b7f4e6f742074686520636f6e7472616374206f776e657200000000000000000000600082015250565b60006116d0601683611689565b91506116db8261169a565b602082019050919050565b600060208201905081810360008301526116ff816116c3565b9050919050565b7f496e76616c6964206e6577206f776e6572000000000000000000000000000000600082015250565b600061173c601183611689565b915061174782611706565b602082019050919050565b6000602082019050818103600083015261176b8161172f565b9050919050565b7f556e617574686f72697a65642073656e64657200000000000000000000000000600082015250565b60006117a8601383611689565b91506117b382611772565b602082019050919050565b600060208201905081810360008301526117d78161179b565b9050919050565b60006117e982611047565b9050919050565b6117f9816117de565b811461180457600080fd5b50565b600081519050611816816117f0565b92915050565b60008151905061182b816111d0565b92915050565b6000806000806080858703121561184b5761184a611127565b5b600061185987828801611807565b945050602061186a8782880161181c565b935050604061187b87828801611807565b925050606061188c8782880161181c565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611901826111c6565b915061190c836111c6565b9250828201905080821115611924576119236118c7565b5b92915050565b7f417262697472616765206c6f7374206d6f6e6579000000000000000000000000600082015250565b6000611960601483611689565b915061196b8261192a565b602082019050919050565b6000602082019050818103600083015261198f81611953565b9050919050565b60006119a1826111c6565b91506119ac836111c6565b92508282039050818111156119c4576119c36118c7565b5b92915050565b6119d3816111c6565b82525050565b60006080820190506119ee60008301876119ca565b6119fb60208301866119ca565b611a0860408301856119ca565b611a1560608301846119ca565b95945050505050565b6000608082019050611a33600083018761119c565b611a4060208301866119ca565b611a4d604083018561119c565b611a5a60608301846119ca565b95945050505050565b6000611a6e82611093565b9050919050565b611a7e81611a63565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000611abb82611093565b9050919050565b611acb81611ab0565b82525050565b6000611add8383611ac2565b60208301905092915050565b6000602082019050919050565b6000611b0182611a84565b611b0b8185611a8f565b9350611b1683611aa0565b8060005b83811015611b47578151611b2e8882611ad1565b9750611b3983611ae9565b925050600181019050611b1a565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b611b89816111c6565b82525050565b6000611b9b8383611b80565b60208301905092915050565b6000602082019050919050565b6000611bbf82611b54565b611bc98185611b5f565b9350611bd483611b70565b8060005b83811015611c05578151611bec8882611b8f565b9750611bf783611ba7565b925050600181019050611bd8565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611c4c578082015181840152602081019050611c31565b60008484015250505050565b6000611c6382611c12565b611c6d8185611c1d565b9350611c7d818560208601611c2e565b611c8681611241565b840191505092915050565b6000608082019050611ca66000830187611a75565b8181036020830152611cb88186611af6565b90508181036040830152611ccc8185611bb4565b90508181036060830152611ce08184611c58565b905095945050505050565b6000604082019050611d00600083018561119c565b611d0d60208301846119ca565b9392505050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000611d4a601f83611689565b9150611d5582611d14565b602082019050919050565b60006020820190508181036000830152611d7981611d3d565b9050919050565b611d8981611131565b82525050565b600062ffffff82169050919050565b611da781611d8f565b82525050565b611db681611047565b82525050565b61010082016000820151611dd36000850182611d80565b506020820151611de66020850182611d80565b506040820151611df96040850182611d9e565b506060820151611e0c6060850182611d80565b506080820151611e1f6080850182611b80565b5060a0820151611e3260a0850182611b80565b5060c0820151611e4560c0850182611b80565b5060e0820151611e5860e0850182611dad565b50505050565b600061010082019050611e746000830184611dbc565b92915050565b600060208284031215611e9057611e8f611127565b5b6000611e9e8482850161181c565b91505092915050565b6000604082019050611ebc600083018561119c565b611ec9602083018461119c565b9392505050565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60008201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000602082015250565b6000611f2c603683611689565b9150611f3782611ed0565b604082019050919050565b60006020820190508181036000830152611f5b81611f1f565b9050919050565b60008115159050919050565b611f7781611f62565b8114611f8257600080fd5b50565b600081519050611f9481611f6e565b92915050565b600060208284031215611fb057611faf611127565b5b6000611fbe84828501611f85565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b6000612023602a83611689565b915061202e82611fc7565b604082019050919050565b6000602082019050818103600083015261205281612016565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b60006120b5602683611689565b91506120c082612059565b604082019050919050565b600060208201905081810360008301526120e4816120a8565b9050919050565b600081905092915050565b600061210182611c12565b61210b81856120eb565b935061211b818560208601611c2e565b80840191505092915050565b600061213382846120f6565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000612174601d83611689565b915061217f8261213e565b602082019050919050565b600060208201905081810360008301526121a381612167565b9050919050565b600081519050919050565b60006121c0826121aa565b6121ca8185611689565b93506121da818560208601611c2e565b6121e381611241565b840191505092915050565b6000602082019050818103600083015261220881846121b5565b90509291505056fea264697066735822122001e794ca984693dc7fc1fbc81adccb70886c1db28660dcad0191b31c2875a54c64736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
-----Decoded View---------------
Arg [0] : _balancerVault (address): 0xBA12222222228d8Ba445958a75a0704d566BF2C8
Arg [1] : _uniswapV3Router (address): 0xE592427A0AEce92De3Edee1F18E0157C05861564
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8
Arg [1] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.