Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 18 from a total of 18 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Make Flash Loan | 23109930 | 217 days ago | IN | 0 ETH | 0.00050546 | ||||
| Make Flash Loan | 23109922 | 217 days ago | IN | 0 ETH | 0.0005061 | ||||
| Make Flash Loan | 23103947 | 218 days ago | IN | 0 ETH | 0.00019485 | ||||
| Make Flash Loan | 23103945 | 218 days ago | IN | 0 ETH | 0.00019942 | ||||
| Make Flash Loan | 23103942 | 218 days ago | IN | 0 ETH | 0.00020326 | ||||
| Make Flash Loan | 23103938 | 218 days ago | IN | 0 ETH | 0.00019859 | ||||
| Make Flash Loan | 23103936 | 218 days ago | IN | 0 ETH | 0.00020343 | ||||
| Make Flash Loan | 23103933 | 218 days ago | IN | 0 ETH | 0.00019564 | ||||
| Make Flash Loan | 23103930 | 218 days ago | IN | 0 ETH | 0.00022507 | ||||
| Make Flash Loan | 23103927 | 218 days ago | IN | 0 ETH | 0.00022275 | ||||
| Make Flash Loan | 23103924 | 218 days ago | IN | 0 ETH | 0.00023483 | ||||
| Make Flash Loan | 23103921 | 218 days ago | IN | 0 ETH | 0.00022005 | ||||
| Make Flash Loan | 23097424 | 219 days ago | IN | 0 ETH | 0.00028537 | ||||
| Make Flash Loan | 23097423 | 219 days ago | IN | 0 ETH | 0.00034423 | ||||
| Make Flash Loan | 23097413 | 219 days ago | IN | 0 ETH | 0.00031234 | ||||
| Make Flash Loan | 23097412 | 219 days ago | IN | 0 ETH | 0.00037487 | ||||
| Make Flash Loan | 23097388 | 219 days ago | IN | 0 ETH | 0.00026216 | ||||
| Make Flash Loan | 23097387 | 219 days ago | IN | 0 ETH | 0.00023981 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FlashLoanRecipient
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./balancer/IVault.sol";
import "./balancer/IFlashLoanRecipient.sol";
interface IUniswapV3Pool {
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
function token0() external view returns (address);
function token1() external view returns (address);
}
interface IUniswapV2Pair {
function swap(
uint amount0Out,
uint amount1Out,
address to,
bytes calldata data
) external;
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112, uint112, uint32);
}
contract FlashLoanRecipient is IFlashLoanRecipient, ReentrancyGuard, Ownable {
IVault private constant vault = IVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
address private profitRecipient;
event Debug(string message, uint256 index, address token, uint256 amount);
event SlippageReverted(uint256 index, address token, uint256 expectedMin, uint256 actual);
event ProfitRecipientChanged(address oldRecipient, address newRecipient);
constructor(address _profitRecipient) Ownable(msg.sender) {
require(_profitRecipient != address(0), "Zero profit recipient");
profitRecipient = _profitRecipient;
}
// -----------------------
// Helpers compatibili USDT
// -----------------------
function _safeApprove(IERC20 token, address spender, uint256 value) internal {
(bool success, bytes memory data) =
address(token).call(abi.encodeWithSelector(token.approve.selector, spender, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "Approve failed");
}
function _safeTransfer(IERC20 token, address to, uint256 value) internal {
(bool success, bytes memory data) =
address(token).call(abi.encodeWithSelector(token.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "Transfer failed");
}
// Avvia il flash loan
function makeFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
address[] memory pool1s,
address[] memory pool2s,
uint256[] memory minOutV3,
uint256[] memory minOutV2
) external nonReentrant {
require(
tokens.length == pool1s.length &&
tokens.length == pool2s.length &&
tokens.length == minOutV3.length &&
tokens.length == minOutV2.length,
"Array length mismatch"
);
bytes memory userData = abi.encode(pool1s, pool2s, minOutV3, minOutV2);
vault.flashLoan(this, tokens, amounts, userData);
}
// Callback dal flash loan
function receiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external override {
require(msg.sender == address(vault), "Invalid sender");
(address[] memory pool1s, address[] memory pool2s, uint256[] memory minOutV3, uint256[] memory minOutV2) =
abi.decode(userData, (address[], address[], uint256[], uint256[]));
require(tokens.length == pool1s.length && tokens.length == pool2s.length, "Array length mismatch");
for (uint i = 0; i < tokens.length; i++) {
IERC20 borrowedToken = tokens[i];
uint256 amountIn = amounts[i];
emit Debug("Before V3 swap", i, address(borrowedToken), amountIn);
IUniswapV3Pool v3pool = IUniswapV3Pool(pool1s[i]);
address token0 = v3pool.token0();
address token1 = v3pool.token1();
bool zeroForOne = address(borrowedToken) == token0;
// Approve compatibile con USDT
_safeApprove(borrowedToken, address(v3pool), 0);
_safeApprove(borrowedToken, address(v3pool), amountIn);
uint160 sqrtPriceLimitX96 = zeroForOne
? uint160(4295128740)
: uint160(1461446703485210103287273052203988822378723970341);
v3pool.swap(
address(this),
zeroForOne,
int256(amountIn),
sqrtPriceLimitX96,
abi.encode(address(borrowedToken))
);
address receivedToken = zeroForOne ? token1 : token0;
IERC20 received = IERC20(receivedToken);
uint256 receivedAmount = received.balanceOf(address(this));
emit Debug("After V3 swap", i, receivedToken, receivedAmount);
if (receivedAmount < minOutV3[i]) {
emit SlippageReverted(i, receivedToken, minOutV3[i], receivedAmount);
revert("Slippage protection V3 failed");
}
IUniswapV2Pair v2pair = IUniswapV2Pair(pool2s[i]);
(uint112 reserve0, uint112 reserve1, ) = v2pair.getReserves();
address v2token0 = v2pair.token0();
address v2token1 = v2pair.token1();
uint256 amount0Out = 0;
uint256 amount1Out = 0;
uint256 amountInWithFee = receivedAmount * 997;
uint256 expectedOut;
if (receivedToken == v2token0) {
expectedOut = (amountInWithFee * uint256(reserve1)) / (uint256(reserve0) * 1000 + amountInWithFee);
amount1Out = expectedOut;
} else if (receivedToken == v2token1) {
expectedOut = (amountInWithFee * uint256(reserve0)) / (uint256(reserve1) * 1000 + amountInWithFee);
amount0Out = expectedOut;
} else {
revert("Received token not in V2 pair");
}
if (expectedOut < minOutV2[i]) {
emit SlippageReverted(i, receivedToken, minOutV2[i], expectedOut);
revert("Slippage protection V2 failed");
}
_safeTransfer(received, address(v2pair), receivedAmount);
v2pair.swap(amount0Out, amount1Out, address(this), "");
emit Debug("After V2 swap", i, address(borrowedToken), borrowedToken.balanceOf(address(this)));
uint256 amountToRepay = amounts[i] + feeAmounts[i];
require(borrowedToken.balanceOf(address(this)) >= amountToRepay, "Insufficient to repay");
_safeTransfer(borrowedToken, address(vault), amountToRepay);
uint256 remaining = borrowedToken.balanceOf(address(this));
if (remaining > 0 && profitRecipient != address(0)) {
_safeTransfer(borrowedToken, profitRecipient, remaining);
}
}
}
// Callback Uniswap V3
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata
) external {
require(amount0Delta > 0 || amount1Delta > 0, "No repayment required");
address tokenToRepay = amount0Delta > 0
? IUniswapV3Pool(msg.sender).token0()
: IUniswapV3Pool(msg.sender).token1();
uint256 repayAmount = uint256(amount0Delta > 0 ? amount0Delta : amount1Delta);
_safeTransfer(IERC20(tokenToRepay), msg.sender, repayAmount);
}
// Admin
function setProfitRecipient(address _recipient) external onlyOwner {
require(_recipient != address(0), "Zero address");
emit ProfitRecipientChanged(profitRecipient, _recipient);
profitRecipient = _recipient;
}
function getProfitRecipient() external view returns (address) {
return profitRecipient;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @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 EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* 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;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
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
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// 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: 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 "@openzeppelin/contracts/token/ERC20/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 "@openzeppelin/contracts/token/ERC20/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 "@openzeppelin/contracts/token/ERC20/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: 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/contracts/token/ERC20/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;
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_profitRecipient","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"message","type":"string"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Debug","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"newRecipient","type":"address"}],"name":"ProfitRecipientChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"expectedMin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actual","type":"uint256"}],"name":"SlippageReverted","type":"event"},{"inputs":[],"name":"getProfitRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address[]","name":"pool1s","type":"address[]"},{"internalType":"address[]","name":"pool2s","type":"address[]"},{"internalType":"uint256[]","name":"minOutV3","type":"uint256[]"},{"internalType":"uint256[]","name":"minOutV2","type":"uint256[]"}],"name":"makeFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","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":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"setProfitRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60803461012657601f611a7038819003918201601f19168301916001600160401b0383118484101761012b5780849260209460405283398101031261012657516001600160a01b0381169081900361012657600160005533156101105760018054336001600160a01b03198216811790925560405191906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a381156100ce5750600280546001600160a01b03191691909117905560405161192e90816101428239f35b62461bcd60e51b815260206004820152601560248201527f5a65726f2070726f66697420726563697069656e7400000000000000000000006044820152606490fd5b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe6080604052600436101561001257600080fd5b60003560e01c80634795084f14611342578063715018a6146112e55780638da5cb5b146112bc578063d26516ac14611293578063f04f27071461054f578063f2fde38b146104c5578063f8a2e8bf146102405763fa461e331461007457600080fd5b34610161576060366003190112610161576024356004356044356001600160401b03811161016157366023820112156101615780600401356001600160401b0381116101615736910160240111610161576000811390818015610236575b156101f9576000821561017a5750604051630dfe168160e01b815292602084600481335afa801561016e5760009061012e575b6101249450925b156101265750905b33906001600160a01b0316611867565b005b905090610114565b506020843d602011610166575b816101486020938361140a565b810103126101615761015c610124946115ac565b610105565b600080fd5b3d915061013b565b6040513d6000823e3d90fd5b60405163d21220a760e01b81529390602085600481335afa9081156101ed5780916101ac575b5061012494509261010c565b90506020853d6020116101e5575b816101c76020938361140a565b810103126101e257506101dc610124946115ac565b386101a0565b80fd5b3d91506101ba565b604051903d90823e3d90fd5b60405162461bcd60e51b8152602060048201526015602482015274139bc81c995c185e5b595b9d081c995c5d5a5c9959605a1b6044820152606490fd5b50600083136100d2565b346101615760c0366003190112610161576004356001600160401b03811161016157610270903690600401611458565b6024356001600160401b0381116101615761028f9036906004016114c6565b906044356001600160401b038111610161576102af90369060040161153e565b906064356001600160401b038111610161576102cf90369060040161153e565b6084356001600160401b038111610161576102ee9036906004016114c6565b9260a4356001600160401b0381116101615761030e9036906004016114c6565b936002600054146104b4576103699461038d61039f9261037b6103ad96600260005561035289518851811490816104a9575b8161049e575b81610493575b50611682565b604051998a97608060208a015260a0890190611785565b878103601f1901604089015290611785565b858103601f19016060870152906117c2565b838103601f19016080850152906117c2565b03601f19810184528361140a565b73ba12222222228d8ba445958a75a0704d566bf2c83b156101615791604051928391632e1c224f60e11b835260848301306004850152608060248501528251809152602060a4850193019060005b818110610471575050506000936104228493610434936003198683030160448701526117c2565b838103600319016064850152906116f0565b03818373ba12222222228d8ba445958a75a0704d566bf2c85af1801561016e57610460575b6001600055005b600061046b9161140a565b80610459565b82516001600160a01b03168552879550602094850194909201916001016103fb565b90508651148d61034c565b855181149150610346565b835181149150610340565b633ee5aeb560e01b60005260046000fd5b34610161576020366003190112610161576104de6113f4565b6104e66117f6565b6001600160a01b0316801561053957600180546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b631e4fbdf760e01b600052600060045260246000fd5b34610161576080366003190112610161576004356001600160401b0381116101615761057f903690600401611458565b6024356001600160401b0381116101615761059e9036906004016114c6565b906044356001600160401b038111610161576105be9036906004016114c6565b606435926001600160401b03841161016157366023850112156101615783600401356105e981611523565b906105f7604051928361140a565b80825260208201953660248383010111610161578160009260246020930189378301015273ba12222222228d8ba445958a75a0704d566bf2c8330361125d5780518101946080826020880197031261016157516001600160401b03811161016157856020610667928401016115c0565b9460408201516001600160401b0381116101615781602061068a928501016115c0565b9160608101516001600160401b038111610161578260206106ad92840101611625565b916080820151916001600160401b038311610161576106cf9201602001611625565b6106e486518851811490816112525750611682565b60005b8651811015610124576001600160a01b0361070282896116c6565b511661070e82876116c6565b517fa4e520cad5ad7e78ef41cf6811175c8f2e843c3923fd4b2ad25841c5b79f5a9060c060405160808152600e60808201526d04265666f726520563320737761760941b60a0820152856020820152846040820152836060820152a16001600160a01b0361077c848c6116c6565b51604051630dfe168160e01b81529116602082600481845afa91821561016e57600092611217575b5060405163d21220a760e01b815292602084600481855afa93841561016e576000946111dc575b5060018060a01b038316851491600080604051602081019063095ea7b360e01b82528460248201528260448201526044815261080860648261140a565b5190828a5af161081661181f565b816111ad575b50156111485760405163095ea7b360e01b602082019081526001600160a01b03831660248301526044820184905260009182919061086781606481015b03601f19810183528261140a565b5190828a5af161087561181f565b8161117e575b5015611148576108f091604091841561112e576401000276a45b60008451938a6020860152602085526108ae868661140a565b855196879586948593630251596160e31b85523060048601528b6024860152604485015260018060a01b0316606484015260a0608484015260a48301906116f0565b03925af1801561016e57611103575b50156110fc57505b6040516370a0823160e01b8152306004820152906001600160a01b03811690602083602481855afa92831561016e576000936110c9575b507fa4e520cad5ad7e78ef41cf6811175c8f2e843c3923fd4b2ad25841c5b79f5a9060c060405160808152600d60808201526c04166746572205633207377617609c1b60a0820152876020820152846040820152856060820152a16109a385886116c6565b518310611050576001600160a01b036109bc868a6116c6565b51169260405192630240bc6b60e21b8452606084600481885afa93841561016e576000908195610ff8575b50604051630dfe168160e01b8152906020826004818a5afa91821561016e57600092610fbd575b5060405163d21220a760e01b8152956020876004818b5afa96871561016e57600097610f82575b5060009687906103e58702948786046103e51488151715610f6e576001600160a01b03168603610ebb575050610a756001600160701b0380921684611745565b91166103e88102908082046103e81490151715610ea557610a9f92610a9991611758565b90611765565b92835b610aac898b6116c6565b518110610e005750509084610ac092611867565b823b156101615760a460009283604051958694859363022c0d9f60e01b855260048501526024840152306044840152608060648401528160848401525af1801561016e57610def575b506040516370a0823160e01b8152306004820152602081602481855afa90811561016e57600091610dbd575b5060c07fa4e520cad5ad7e78ef41cf6811175c8f2e843c3923fd4b2ad25841c5b79f5a90916040519060808252600d60808301526c04166746572205632207377617609c1b60a08301528560208301528460408301526060820152a1610bb0610b9e83886116c6565b51610ba9848a6116c6565b5190611758565b6040516370a0823160e01b8152306004820152602081602481865afa801561016e578291600091610d89575b5010610d4c5760008091604051602081019163a9059cbb60e01b835273ba12222222228d8ba445958a75a0704d566bf2c86024830152604482015260448152610c2660648261140a565b519082855af1610c3461181f565b81610d1d575b5015610ce6576040516370a0823160e01b8152306004820152602081602481855afa90811561016e57600091610cb4575b50908160019392151580610ca2575b610c87575b5050016106e7565b610c9b91848060a01b036002541690611867565b8980610c7f565b50838060a01b03600254161515610c7a565b906020823d8211610cde575b81610ccd6020938361140a565b810103126101e25750516001610c6b565b3d9150610cc0565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b8051801592508215610d32575b50508a610c3a565b610d45925060208091830101910161184f565b8a80610d2a565b60405162461bcd60e51b8152602060048201526015602482015274496e73756666696369656e7420746f20726570617960581b6044820152606490fd5b91506020823d8211610db5575b81610da36020938361140a565b810103126101e257508190518c610bdc565b3d9150610d96565b906020823d8211610de7575b81610dd66020938361140a565b810103126101e257505160c0610b35565b3d9150610dc9565b6000610dfa9161140a565b89610b09565b9088610e5d7f317f97aa5f6a684d0fa95caed7460e117331b46f89a417039f7893851d3a355193610e31838e6116c6565b5160405194859485909493926060926080830196835260018060a01b0316602083015260408201520152565b0390a160405162461bcd60e51b815260206004820152601d60248201527f536c6970706167652070726f74656374696f6e205632206661696c65640000006044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b9697909691939290916001600160a01b03168503610f2957610ee76001600160701b0380921684611745565b9316906103e88202918083046103e81490151715610f155750610f0e9291610a9991611758565b9384610aa2565b634e487b7160e01b81526011600452602490fd5b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420746f6b656e206e6f7420696e20563220706169720000006044820152606490fd5b634e487b7160e01b8a52601160045260248afd5b90966020823d8211610fb5575b81610f9c6020938361140a565b810103126101e25750610fae906115ac565b9538610a35565b3d9150610f8f565b90916020823d8211610ff0575b81610fd76020938361140a565b810103126101e25750610fe9906115ac565b9038610a0e565b3d9150610fca565b94506060853d8211611048575b816110126060938361140a565b810103126101e25761102385611731565b90604061103260208801611731565b96015163ffffffff8116036101e257508f6109e7565b3d9150611005565b7f317f97aa5f6a684d0fa95caed7460e117331b46f89a417039f7893851d3a3551908561108185610e31838c6116c6565b0390a160405162461bcd60e51b815260206004820152601d60248201527f536c6970706167652070726f74656374696f6e205633206661696c65640000006044820152606490fd5b90926020823d82116110f4575b816110e36020938361140a565b810103126101e2575051918c61093e565b3d91506110d6565b9050610907565b604090813d8111611127575b611119818361140a565b81010312610161578c6108ff565b503d61110f565b73fffd8963efd1fc6a506488495d951d5263988d25610895565b60405162461bcd60e51b815260206004820152600e60248201526d105c1c1c9bdd994819985a5b195960921b6044820152606490fd5b8051801592508215611193575b50508f61087b565b6111a6925060208091830101910161184f565b8f8061118b565b80518015925082156111c2575b50508f61081c565b6111d5925060208091830101910161184f565b8f806111ba565b90936020823d821161120f575b816111f66020938361140a565b810103126101e25750611208906115ac565b928d6107cb565b3d91506111e9565b90916020823d821161124a575b816112316020938361140a565b810103126101e25750611243906115ac565b908c6107a4565b3d9150611224565b90508451148961034c565b60405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b2b73232b960911b6044820152606490fd5b34610161576000366003190112610161576002546040516001600160a01b039091168152602090f35b34610161576000366003190112610161576001546040516001600160a01b039091168152602090f35b34610161576000366003190112610161576112fe6117f6565b600180546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101615760203660031901126101615761135b6113f4565b6113636117f6565b6001600160a01b031680156113c057600254604080516001600160a01b0383168152602081018490527f775a2ba9b69ac883c33736c033e0d9a239021300d43288bc9033482b30dbce6b9190a16001600160a01b03191617600255005b60405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606490fd5b600435906001600160a01b038216820361016157565b90601f801991011681019081106001600160401b0382111761142b57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161142b5760051b60200190565b9080601f830112156101615781359061147082611441565b9261147e604051948561140a565b82845260208085019360051b82010191821161016157602001915b8183106114a65750505090565b82356001600160a01b038116810361016157815260209283019201611499565b9080601f830112156101615781356114dd81611441565b926114eb604051948561140a565b81845260208085019260051b82010192831161016157602001905b8282106115135750505090565b8135815260209182019101611506565b6001600160401b03811161142b57601f01601f191660200190565b9080601f830112156101615781359061155682611441565b92611564604051948561140a565b82845260208085019360051b82010191821161016157602001915b81831061158c5750505090565b82356001600160a01b03811681036101615781526020928301920161157f565b51906001600160a01b038216820361016157565b9080601f830112156101615781516115d781611441565b926115e5604051948561140a565b81845260208085019260051b82010192831161016157602001905b82821061160d5750505090565b6020809161161a846115ac565b815201910190611600565b9080601f8301121561016157815161163c81611441565b9261164a604051948561140a565b81845260208085019260051b82010192831161016157602001905b8282106116725750505090565b8151815260209182019101611665565b1561168957565b60405162461bcd60e51b8152602060048201526015602482015274082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b6044820152606490fd5b80518210156116da5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b919082519283825260005b84811061171c575050826000602080949584010152601f8019910116010190565b806020809284010151828286010152016116fb565b51906001600160701b038216820361016157565b81810292918115918404141715610ea557565b91908201809211610ea557565b811561176f570490565b634e487b7160e01b600052601260045260246000fd5b906020808351928381520192019060005b8181106117a35750505090565b82516001600160a01b0316845260209384019390920191600101611796565b906020808351928381520192019060005b8181106117e05750505090565b82518452602093840193909201916001016117d3565b6001546001600160a01b0316330361180a57565b63118cdaa760e01b6000523360045260246000fd5b3d1561184a573d9061183082611523565b9161183e604051938461140a565b82523d6000602084013e565b606090565b90816020910312610161575180151581036101615790565b60405163a9059cbb60e01b602082019081526001600160a01b039093166024820152604481019390935260009283929083906118a68160648101610859565b51926001600160a01b03165af16118bb61181f565b816118c9575b5015610ce657565b80518015925082156118de575b5050386118c1565b6118f1925060208091830101910161184f565b38806118d656fea2646970667358221220bce6ef92bdbe2f2902e13464da73e6c5114d85b991080a3932273026944a96b264736f6c634300081c0033000000000000000000000000218eb5b2b4bfbcc2d90d0e975982ebc73b0a3061
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c80634795084f14611342578063715018a6146112e55780638da5cb5b146112bc578063d26516ac14611293578063f04f27071461054f578063f2fde38b146104c5578063f8a2e8bf146102405763fa461e331461007457600080fd5b34610161576060366003190112610161576024356004356044356001600160401b03811161016157366023820112156101615780600401356001600160401b0381116101615736910160240111610161576000811390818015610236575b156101f9576000821561017a5750604051630dfe168160e01b815292602084600481335afa801561016e5760009061012e575b6101249450925b156101265750905b33906001600160a01b0316611867565b005b905090610114565b506020843d602011610166575b816101486020938361140a565b810103126101615761015c610124946115ac565b610105565b600080fd5b3d915061013b565b6040513d6000823e3d90fd5b60405163d21220a760e01b81529390602085600481335afa9081156101ed5780916101ac575b5061012494509261010c565b90506020853d6020116101e5575b816101c76020938361140a565b810103126101e257506101dc610124946115ac565b386101a0565b80fd5b3d91506101ba565b604051903d90823e3d90fd5b60405162461bcd60e51b8152602060048201526015602482015274139bc81c995c185e5b595b9d081c995c5d5a5c9959605a1b6044820152606490fd5b50600083136100d2565b346101615760c0366003190112610161576004356001600160401b03811161016157610270903690600401611458565b6024356001600160401b0381116101615761028f9036906004016114c6565b906044356001600160401b038111610161576102af90369060040161153e565b906064356001600160401b038111610161576102cf90369060040161153e565b6084356001600160401b038111610161576102ee9036906004016114c6565b9260a4356001600160401b0381116101615761030e9036906004016114c6565b936002600054146104b4576103699461038d61039f9261037b6103ad96600260005561035289518851811490816104a9575b8161049e575b81610493575b50611682565b604051998a97608060208a015260a0890190611785565b878103601f1901604089015290611785565b858103601f19016060870152906117c2565b838103601f19016080850152906117c2565b03601f19810184528361140a565b73ba12222222228d8ba445958a75a0704d566bf2c83b156101615791604051928391632e1c224f60e11b835260848301306004850152608060248501528251809152602060a4850193019060005b818110610471575050506000936104228493610434936003198683030160448701526117c2565b838103600319016064850152906116f0565b03818373ba12222222228d8ba445958a75a0704d566bf2c85af1801561016e57610460575b6001600055005b600061046b9161140a565b80610459565b82516001600160a01b03168552879550602094850194909201916001016103fb565b90508651148d61034c565b855181149150610346565b835181149150610340565b633ee5aeb560e01b60005260046000fd5b34610161576020366003190112610161576104de6113f4565b6104e66117f6565b6001600160a01b0316801561053957600180546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b631e4fbdf760e01b600052600060045260246000fd5b34610161576080366003190112610161576004356001600160401b0381116101615761057f903690600401611458565b6024356001600160401b0381116101615761059e9036906004016114c6565b906044356001600160401b038111610161576105be9036906004016114c6565b606435926001600160401b03841161016157366023850112156101615783600401356105e981611523565b906105f7604051928361140a565b80825260208201953660248383010111610161578160009260246020930189378301015273ba12222222228d8ba445958a75a0704d566bf2c8330361125d5780518101946080826020880197031261016157516001600160401b03811161016157856020610667928401016115c0565b9460408201516001600160401b0381116101615781602061068a928501016115c0565b9160608101516001600160401b038111610161578260206106ad92840101611625565b916080820151916001600160401b038311610161576106cf9201602001611625565b6106e486518851811490816112525750611682565b60005b8651811015610124576001600160a01b0361070282896116c6565b511661070e82876116c6565b517fa4e520cad5ad7e78ef41cf6811175c8f2e843c3923fd4b2ad25841c5b79f5a9060c060405160808152600e60808201526d04265666f726520563320737761760941b60a0820152856020820152846040820152836060820152a16001600160a01b0361077c848c6116c6565b51604051630dfe168160e01b81529116602082600481845afa91821561016e57600092611217575b5060405163d21220a760e01b815292602084600481855afa93841561016e576000946111dc575b5060018060a01b038316851491600080604051602081019063095ea7b360e01b82528460248201528260448201526044815261080860648261140a565b5190828a5af161081661181f565b816111ad575b50156111485760405163095ea7b360e01b602082019081526001600160a01b03831660248301526044820184905260009182919061086781606481015b03601f19810183528261140a565b5190828a5af161087561181f565b8161117e575b5015611148576108f091604091841561112e576401000276a45b60008451938a6020860152602085526108ae868661140a565b855196879586948593630251596160e31b85523060048601528b6024860152604485015260018060a01b0316606484015260a0608484015260a48301906116f0565b03925af1801561016e57611103575b50156110fc57505b6040516370a0823160e01b8152306004820152906001600160a01b03811690602083602481855afa92831561016e576000936110c9575b507fa4e520cad5ad7e78ef41cf6811175c8f2e843c3923fd4b2ad25841c5b79f5a9060c060405160808152600d60808201526c04166746572205633207377617609c1b60a0820152876020820152846040820152856060820152a16109a385886116c6565b518310611050576001600160a01b036109bc868a6116c6565b51169260405192630240bc6b60e21b8452606084600481885afa93841561016e576000908195610ff8575b50604051630dfe168160e01b8152906020826004818a5afa91821561016e57600092610fbd575b5060405163d21220a760e01b8152956020876004818b5afa96871561016e57600097610f82575b5060009687906103e58702948786046103e51488151715610f6e576001600160a01b03168603610ebb575050610a756001600160701b0380921684611745565b91166103e88102908082046103e81490151715610ea557610a9f92610a9991611758565b90611765565b92835b610aac898b6116c6565b518110610e005750509084610ac092611867565b823b156101615760a460009283604051958694859363022c0d9f60e01b855260048501526024840152306044840152608060648401528160848401525af1801561016e57610def575b506040516370a0823160e01b8152306004820152602081602481855afa90811561016e57600091610dbd575b5060c07fa4e520cad5ad7e78ef41cf6811175c8f2e843c3923fd4b2ad25841c5b79f5a90916040519060808252600d60808301526c04166746572205632207377617609c1b60a08301528560208301528460408301526060820152a1610bb0610b9e83886116c6565b51610ba9848a6116c6565b5190611758565b6040516370a0823160e01b8152306004820152602081602481865afa801561016e578291600091610d89575b5010610d4c5760008091604051602081019163a9059cbb60e01b835273ba12222222228d8ba445958a75a0704d566bf2c86024830152604482015260448152610c2660648261140a565b519082855af1610c3461181f565b81610d1d575b5015610ce6576040516370a0823160e01b8152306004820152602081602481855afa90811561016e57600091610cb4575b50908160019392151580610ca2575b610c87575b5050016106e7565b610c9b91848060a01b036002541690611867565b8980610c7f565b50838060a01b03600254161515610c7a565b906020823d8211610cde575b81610ccd6020938361140a565b810103126101e25750516001610c6b565b3d9150610cc0565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b8051801592508215610d32575b50508a610c3a565b610d45925060208091830101910161184f565b8a80610d2a565b60405162461bcd60e51b8152602060048201526015602482015274496e73756666696369656e7420746f20726570617960581b6044820152606490fd5b91506020823d8211610db5575b81610da36020938361140a565b810103126101e257508190518c610bdc565b3d9150610d96565b906020823d8211610de7575b81610dd66020938361140a565b810103126101e257505160c0610b35565b3d9150610dc9565b6000610dfa9161140a565b89610b09565b9088610e5d7f317f97aa5f6a684d0fa95caed7460e117331b46f89a417039f7893851d3a355193610e31838e6116c6565b5160405194859485909493926060926080830196835260018060a01b0316602083015260408201520152565b0390a160405162461bcd60e51b815260206004820152601d60248201527f536c6970706167652070726f74656374696f6e205632206661696c65640000006044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b9697909691939290916001600160a01b03168503610f2957610ee76001600160701b0380921684611745565b9316906103e88202918083046103e81490151715610f155750610f0e9291610a9991611758565b9384610aa2565b634e487b7160e01b81526011600452602490fd5b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420746f6b656e206e6f7420696e20563220706169720000006044820152606490fd5b634e487b7160e01b8a52601160045260248afd5b90966020823d8211610fb5575b81610f9c6020938361140a565b810103126101e25750610fae906115ac565b9538610a35565b3d9150610f8f565b90916020823d8211610ff0575b81610fd76020938361140a565b810103126101e25750610fe9906115ac565b9038610a0e565b3d9150610fca565b94506060853d8211611048575b816110126060938361140a565b810103126101e25761102385611731565b90604061103260208801611731565b96015163ffffffff8116036101e257508f6109e7565b3d9150611005565b7f317f97aa5f6a684d0fa95caed7460e117331b46f89a417039f7893851d3a3551908561108185610e31838c6116c6565b0390a160405162461bcd60e51b815260206004820152601d60248201527f536c6970706167652070726f74656374696f6e205633206661696c65640000006044820152606490fd5b90926020823d82116110f4575b816110e36020938361140a565b810103126101e2575051918c61093e565b3d91506110d6565b9050610907565b604090813d8111611127575b611119818361140a565b81010312610161578c6108ff565b503d61110f565b73fffd8963efd1fc6a506488495d951d5263988d25610895565b60405162461bcd60e51b815260206004820152600e60248201526d105c1c1c9bdd994819985a5b195960921b6044820152606490fd5b8051801592508215611193575b50508f61087b565b6111a6925060208091830101910161184f565b8f8061118b565b80518015925082156111c2575b50508f61081c565b6111d5925060208091830101910161184f565b8f806111ba565b90936020823d821161120f575b816111f66020938361140a565b810103126101e25750611208906115ac565b928d6107cb565b3d91506111e9565b90916020823d821161124a575b816112316020938361140a565b810103126101e25750611243906115ac565b908c6107a4565b3d9150611224565b90508451148961034c565b60405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b2b73232b960911b6044820152606490fd5b34610161576000366003190112610161576002546040516001600160a01b039091168152602090f35b34610161576000366003190112610161576001546040516001600160a01b039091168152602090f35b34610161576000366003190112610161576112fe6117f6565b600180546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101615760203660031901126101615761135b6113f4565b6113636117f6565b6001600160a01b031680156113c057600254604080516001600160a01b0383168152602081018490527f775a2ba9b69ac883c33736c033e0d9a239021300d43288bc9033482b30dbce6b9190a16001600160a01b03191617600255005b60405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606490fd5b600435906001600160a01b038216820361016157565b90601f801991011681019081106001600160401b0382111761142b57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161142b5760051b60200190565b9080601f830112156101615781359061147082611441565b9261147e604051948561140a565b82845260208085019360051b82010191821161016157602001915b8183106114a65750505090565b82356001600160a01b038116810361016157815260209283019201611499565b9080601f830112156101615781356114dd81611441565b926114eb604051948561140a565b81845260208085019260051b82010192831161016157602001905b8282106115135750505090565b8135815260209182019101611506565b6001600160401b03811161142b57601f01601f191660200190565b9080601f830112156101615781359061155682611441565b92611564604051948561140a565b82845260208085019360051b82010191821161016157602001915b81831061158c5750505090565b82356001600160a01b03811681036101615781526020928301920161157f565b51906001600160a01b038216820361016157565b9080601f830112156101615781516115d781611441565b926115e5604051948561140a565b81845260208085019260051b82010192831161016157602001905b82821061160d5750505090565b6020809161161a846115ac565b815201910190611600565b9080601f8301121561016157815161163c81611441565b9261164a604051948561140a565b81845260208085019260051b82010192831161016157602001905b8282106116725750505090565b8151815260209182019101611665565b1561168957565b60405162461bcd60e51b8152602060048201526015602482015274082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b6044820152606490fd5b80518210156116da5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b919082519283825260005b84811061171c575050826000602080949584010152601f8019910116010190565b806020809284010151828286010152016116fb565b51906001600160701b038216820361016157565b81810292918115918404141715610ea557565b91908201809211610ea557565b811561176f570490565b634e487b7160e01b600052601260045260246000fd5b906020808351928381520192019060005b8181106117a35750505090565b82516001600160a01b0316845260209384019390920191600101611796565b906020808351928381520192019060005b8181106117e05750505090565b82518452602093840193909201916001016117d3565b6001546001600160a01b0316330361180a57565b63118cdaa760e01b6000523360045260246000fd5b3d1561184a573d9061183082611523565b9161183e604051938461140a565b82523d6000602084013e565b606090565b90816020910312610161575180151581036101615790565b60405163a9059cbb60e01b602082019081526001600160a01b039093166024820152604481019390935260009283929083906118a68160648101610859565b51926001600160a01b03165af16118bb61181f565b816118c9575b5015610ce657565b80518015925082156118de575b5050386118c1565b6118f1925060208091830101910161184f565b38806118d656fea2646970667358221220bce6ef92bdbe2f2902e13464da73e6c5114d85b991080a3932273026944a96b264736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000218eb5b2b4bfbcc2d90d0e975982ebc73b0a3061
-----Decoded View---------------
Arg [0] : _profitRecipient (address): 0x218EB5B2b4BFBcC2D90d0e975982ebC73B0a3061
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000218eb5b2b4bfbcc2d90d0e975982ebc73b0a3061
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.