Transaction Hash:
Block:
10566801 at Jul-31-2020 10:27:54 AM +UTC
Transaction Fee:
0.00498888 ETH
$10.09
Gas Used:
41,574 Gas / 120 Gwei
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x829BD824...93333A830
Miner
| (F2Pool Old) | 3,482.886507119325111541 Eth | 3,482.891495999325111541 Eth | 0.00498888 | |
| 0xf2065Db5...cc5b179BF |
43.527390855239896827 Eth
Nonce: 265
|
43.522401975239896827 Eth
Nonce: 266
| 0.00498888 |
Execution Trace
ExchangeProxy.batchSwapExactIn( swaps=, tokenIn=0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83, tokenOut=0x6B175474E89094C44Da98b954EedeAC495271d0F, totalAmountIn=8000000000000000000, minTotalAmountOut=4529035048302893050270 ) => ( totalAmountOut=3963877391197344453575983046348115674221700746820753546331534351508065746944 )
-
YFII.transferFrom( sender=0xf2065Db56Fde1B56e60F66a0dcB2743cc5b179BF, recipient=0x6317C5e82A06E1d8bf200d21F4510Ac2c038AC81, amount=8000000000000000000 )
batchSwapExactIn[ExchangeProxy (ln:73)]
transferFrom[ExchangeProxy (ln:87)]allowance[ExchangeProxy (ln:92)]approve[ExchangeProxy (ln:93)]swapExactAmountIn[ExchangeProxy (ln:95)]add[ExchangeProxy (ln:102)]transfer[ExchangeProxy (ln:105)]balanceOf[ExchangeProxy (ln:105)]transfer[ExchangeProxy (ln:106)]balanceOf[ExchangeProxy (ln:106)]
File 1 of 2: ExchangeProxy
File 2 of 2: YFII
// 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.5.12;
pragma experimental ABIEncoderV2;
contract PoolInterface {
function swapExactAmountIn(address, uint, address, uint, uint) external returns (uint, uint);
function swapExactAmountOut(address, uint, address, uint, uint) external returns (uint, uint);
}
contract TokenInterface {
function balanceOf(address) public returns (uint);
function allowance(address, address) public returns (uint);
function approve(address, uint) public returns (bool);
function transfer(address, uint) public returns (bool);
function transferFrom(address, address, uint) public returns (bool);
function deposit() public payable;
function withdraw(uint) public;
}
contract ExchangeProxy {
struct Swap {
address pool;
uint tokenInParam; // tokenInAmount / maxAmountIn / limitAmountIn
uint tokenOutParam; // minAmountOut / tokenAmountOut / limitAmountOut
uint maxPrice;
}
event LOG_CALL(
bytes4 indexed sig,
address indexed caller,
bytes data
) anonymous;
modifier _logs_() {
emit LOG_CALL(msg.sig, msg.sender, msg.data);
_;
}
modifier _lock_() {
require(!_mutex, "ERR_REENTRY");
_mutex = true;
_;
_mutex = false;
}
bool private _mutex;
TokenInterface weth;
constructor(address _weth) public {
weth = TokenInterface(_weth);
}
function add(uint a, uint b) internal pure returns (uint) {
uint c = a + b;
require(c >= a, "ERR_ADD_OVERFLOW");
return c;
}
function batchSwapExactIn(
Swap[] memory swaps,
address tokenIn,
address tokenOut,
uint totalAmountIn,
uint minTotalAmountOut
)
public
_logs_
_lock_
returns (uint totalAmountOut)
{
TokenInterface TI = TokenInterface(tokenIn);
TokenInterface TO = TokenInterface(tokenOut);
require(TI.transferFrom(msg.sender, address(this), totalAmountIn), "ERR_TRANSFER_FAILED");
for (uint i = 0; i < swaps.length; i++) {
Swap memory swap = swaps[i];
PoolInterface pool = PoolInterface(swap.pool);
if (TI.allowance(address(this), swap.pool) < totalAmountIn) {
TI.approve(swap.pool, uint(-1));
}
(uint tokenAmountOut,) = pool.swapExactAmountIn(
tokenIn,
swap.tokenInParam,
tokenOut,
swap.tokenOutParam,
swap.maxPrice
);
totalAmountOut = add(tokenAmountOut, totalAmountOut);
}
require(totalAmountOut >= minTotalAmountOut, "ERR_LIMIT_OUT");
require(TO.transfer(msg.sender, TO.balanceOf(address(this))), "ERR_TRANSFER_FAILED");
require(TI.transfer(msg.sender, TI.balanceOf(address(this))), "ERR_TRANSFER_FAILED");
return totalAmountOut;
}
function batchSwapExactOut(
Swap[] memory swaps,
address tokenIn,
address tokenOut,
uint maxTotalAmountIn
)
public
_logs_
_lock_
returns (uint totalAmountIn)
{
TokenInterface TI = TokenInterface(tokenIn);
TokenInterface TO = TokenInterface(tokenOut);
require(TI.transferFrom(msg.sender, address(this), maxTotalAmountIn), "ERR_TRANSFER_FAILED");
for (uint i = 0; i < swaps.length; i++) {
Swap memory swap = swaps[i];
PoolInterface pool = PoolInterface(swap.pool);
if (TI.allowance(address(this), swap.pool) < maxTotalAmountIn) {
TI.approve(swap.pool, uint(-1));
}
(uint tokenAmountIn,) = pool.swapExactAmountOut(
tokenIn,
swap.tokenInParam,
tokenOut,
swap.tokenOutParam,
swap.maxPrice
);
totalAmountIn = add(tokenAmountIn, totalAmountIn);
}
require(totalAmountIn <= maxTotalAmountIn, "ERR_LIMIT_IN");
require(TO.transfer(msg.sender, TO.balanceOf(address(this))), "ERR_TRANSFER_FAILED");
require(TI.transfer(msg.sender, TI.balanceOf(address(this))), "ERR_TRANSFER_FAILED");
return totalAmountIn;
}
function batchEthInSwapExactIn(
Swap[] memory swaps,
address tokenOut,
uint minTotalAmountOut
)
public payable
_logs_
_lock_
returns (uint totalAmountOut)
{
TokenInterface TO = TokenInterface(tokenOut);
weth.deposit.value(msg.value)();
for (uint i = 0; i < swaps.length; i++) {
Swap memory swap = swaps[i];
PoolInterface pool = PoolInterface(swap.pool);
if (weth.allowance(address(this), swap.pool) < msg.value) {
weth.approve(swap.pool, uint(-1));
}
(uint tokenAmountOut,) = pool.swapExactAmountIn(
address(weth),
swap.tokenInParam,
tokenOut,
swap.tokenOutParam,
swap.maxPrice
);
totalAmountOut = add(tokenAmountOut, totalAmountOut);
}
require(totalAmountOut >= minTotalAmountOut, "ERR_LIMIT_OUT");
require(TO.transfer(msg.sender, TO.balanceOf(address(this))), "ERR_TRANSFER_FAILED");
uint wethBalance = weth.balanceOf(address(this));
if (wethBalance > 0) {
weth.withdraw(wethBalance);
(bool xfer,) = msg.sender.call.value(wethBalance)("");
require(xfer, "ERR_ETH_FAILED");
}
return totalAmountOut;
}
function batchEthOutSwapExactIn(
Swap[] memory swaps,
address tokenIn,
uint totalAmountIn,
uint minTotalAmountOut
)
public
_logs_
_lock_
returns (uint totalAmountOut)
{
TokenInterface TI = TokenInterface(tokenIn);
require(TI.transferFrom(msg.sender, address(this), totalAmountIn), "ERR_TRANSFER_FAILED");
for (uint i = 0; i < swaps.length; i++) {
Swap memory swap = swaps[i];
PoolInterface pool = PoolInterface(swap.pool);
if (TI.allowance(address(this), swap.pool) < totalAmountIn) {
TI.approve(swap.pool, uint(-1));
}
(uint tokenAmountOut,) = pool.swapExactAmountIn(
tokenIn,
swap.tokenInParam,
address(weth),
swap.tokenOutParam,
swap.maxPrice
);
totalAmountOut = add(tokenAmountOut, totalAmountOut);
}
require(totalAmountOut >= minTotalAmountOut, "ERR_LIMIT_OUT");
uint wethBalance = weth.balanceOf(address(this));
weth.withdraw(wethBalance);
(bool xfer,) = msg.sender.call.value(wethBalance)("");
require(xfer, "ERR_ETH_FAILED");
require(TI.transfer(msg.sender, TI.balanceOf(address(this))), "ERR_TRANSFER_FAILED");
return totalAmountOut;
}
function batchEthInSwapExactOut(
Swap[] memory swaps,
address tokenOut
)
public payable
_logs_
_lock_
returns (uint totalAmountIn)
{
TokenInterface TO = TokenInterface(tokenOut);
weth.deposit.value(msg.value)();
for (uint i = 0; i < swaps.length; i++) {
Swap memory swap = swaps[i];
PoolInterface pool = PoolInterface(swap.pool);
if (weth.allowance(address(this), swap.pool) < msg.value) {
weth.approve(swap.pool, uint(-1));
}
(uint tokenAmountIn,) = pool.swapExactAmountOut(
address(weth),
swap.tokenInParam,
tokenOut,
swap.tokenOutParam,
swap.maxPrice
);
totalAmountIn = add(tokenAmountIn, totalAmountIn);
}
require(TO.transfer(msg.sender, TO.balanceOf(address(this))), "ERR_TRANSFER_FAILED");
uint wethBalance = weth.balanceOf(address(this));
if (wethBalance > 0) {
weth.withdraw(wethBalance);
(bool xfer,) = msg.sender.call.value(wethBalance)("");
require(xfer, "ERR_ETH_FAILED");
}
return totalAmountIn;
}
function batchEthOutSwapExactOut(
Swap[] memory swaps,
address tokenIn,
uint maxTotalAmountIn
)
public
_logs_
_lock_
returns (uint totalAmountIn)
{
TokenInterface TI = TokenInterface(tokenIn);
require(TI.transferFrom(msg.sender, address(this), maxTotalAmountIn), "ERR_TRANSFER_FAILED");
for (uint i = 0; i < swaps.length; i++) {
Swap memory swap = swaps[i];
PoolInterface pool = PoolInterface(swap.pool);
if (TI.allowance(address(this), swap.pool) < maxTotalAmountIn) {
TI.approve(swap.pool, uint(-1));
}
(uint tokenAmountIn,) = pool.swapExactAmountOut(
tokenIn,
swap.tokenInParam,
address(weth),
swap.tokenOutParam,
swap.maxPrice
);
totalAmountIn = add(tokenAmountIn, totalAmountIn);
}
require(totalAmountIn <= maxTotalAmountIn, "ERR_LIMIT_IN");
require(TI.transfer(msg.sender, TI.balanceOf(address(this))), "ERR_TRANSFER_FAILED");
uint wethBalance = weth.balanceOf(address(this));
weth.withdraw(wethBalance);
(bool xfer,) = msg.sender.call.value(wethBalance)("");
require(xfer, "ERR_ETH_FAILED");
return totalAmountIn;
}
function() external payable {}
}File 2 of 2: YFII
pragma solidity ^0.5.16;
interface IERC20 {
function totalSupply() external view returns (uint);
function balanceOf(address account) external view returns (uint);
function transfer(address recipient, uint amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint amount) external returns (bool);
function transferFrom(address sender, address recipient, uint amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
contract Context {
constructor () internal { }
// solhint-disable-previous-line no-empty-blocks
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
}
contract ERC20 is Context, IERC20 {
using SafeMath for uint;
mapping (address => uint) private _balances;
mapping (address => mapping (address => uint)) private _allowances;
uint private _totalSupply;
function totalSupply() public view returns (uint) {
return _totalSupply;
}
function balanceOf(address account) public view returns (uint) {
return _balances[account];
}
function transfer(address recipient, uint amount) public returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view returns (uint) {
return _allowances[owner][spender];
}
function approve(address spender, uint amount) public returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint amount) public returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
function increaseAllowance(address spender, uint addedValue) public returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint subtractedValue) public returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function _transfer(address sender, address recipient, uint amount) internal {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint amount) internal {
require(account != address(0), "ERC20: mint to the zero address");
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint amount) internal {
require(account != address(0), "ERC20: burn from the zero address");
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint amount) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
}
contract ERC20Detailed is IERC20 {
string private _name;
string private _symbol;
uint8 private _decimals;
constructor (string memory name, string memory symbol, uint8 decimals) public {
_name = name;
_symbol = symbol;
_decimals = decimals;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
}
library SafeMath {
function add(uint a, uint b) internal pure returns (uint) {
uint c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint a, uint b) internal pure returns (uint) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
require(b <= a, errorMessage);
uint c = a - b;
return c;
}
function mul(uint a, uint b) internal pure returns (uint) {
if (a == 0) {
return 0;
}
uint c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint a, uint b) internal pure returns (uint) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint c = a / b;
return c;
}
}
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != 0x0 && codehash != accountHash);
}
}
library SafeERC20 {
using SafeMath for uint;
using Address for address;
function safeTransfer(IERC20 token, address to, uint value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function callOptionalReturn(IERC20 token, bytes memory data) private {
require(address(token).isContract(), "SafeERC20: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
contract YFII is ERC20, ERC20Detailed {
using SafeERC20 for IERC20;
using Address for address;
using SafeMath for uint;
address public governance;
mapping (address => bool) public minters;
constructor () public ERC20Detailed("YFII.finance", "YFII", 18) {
governance = tx.origin;
}
function mint(address account, uint256 amount) public {
require(minters[msg.sender], "!minter");
_mint(account, amount);
}
function setGovernance(address _governance) public {
require(msg.sender == governance, "!governance");
governance = _governance;
}
function addMinter(address _minter) public {
require(msg.sender == governance, "!governance");
minters[_minter] = true;
}
function removeMinter(address _minter) public {
require(msg.sender == governance, "!governance");
minters[_minter] = false;
}
}