ETH Price: $2,023.18 (+0.09%)

Transaction Decoder

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 Code
(F2Pool Old)
3,482.886507119325111541 Eth3,482.891495999325111541 Eth0.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 )
    File 1 of 2: ExchangeProxy
    // 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;
      }
    }