ETH Price: $1,980.02 (-3.31%)
Gas: 0.18 Gwei

Transaction Decoder

Block:
13576220 at Nov-08-2021 02:06:28 PM +UTC
Transaction Fee:
0.014002553885588218 ETH $27.73
Gas Used:
140,678 Gas / 99.536202431 Gwei

Emitted Events:

295 Dai.Transfer( src=0xfc7b1daD07111c77c5d619043D75aC9A19680760, dst=0x27239549DD40E1D60F5B80B0C4196923745B1FD2, wad=133148371726188000000 )
296 0xfc7b1dad07111c77c5d619043d75ac9a19680760.0x8cf3dec1929508e5677d7db003124e74802bfba7250a572205a9986d86ca9f1e( 0x8cf3dec1929508e5677d7db003124e74802bfba7250a572205a9986d86ca9f1e, 00000000000000000000000027239549dd40e1d60f5b80b0c4196923745b1fd2, 02d7d917fe02447571db7bd0ea4401dc6844be52695f7bf8b4e1d8abd8c4ea48, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f, 00000000000000000000000000000000000000000000000000646823a6a46000, 00000000000000000000000000000000000000000000000737ce0aa27919b300 )
297 Dai.Transfer( src=0x27239549DD40E1D60F5B80B0C4196923745B1FD2, dst=[Sender] 0x9ff7a776a46a53a70d941dc0b11510dea6c04ee4, wad=133148371726188000000 )
298 AggregationRouterV3.Swapped( sender=[Sender] 0x9ff7a776a46a53a70d941dc0b11510dea6c04ee4, srcToken=0xEeeeeEee...eeeeeEEeE, dstToken=Dai, dstReceiver=[Sender] 0x9ff7a776a46a53a70d941dc0b11510dea6c04ee4, spentAmount=28262000000000000, returnAmount=133148371726188000000 )

Account State Difference:

  Address   Before After State Difference Code
0x6B175474...495271d0F
(F2Pool Old)
2,846.628849237829336193 Eth2,846.629017670575725777 Eth0.000168432746389584
0x9Ff7A776...ea6C04EE4
0.056524 Eth
Nonce: 0
0.014259446114411782 Eth
Nonce: 1
0.042264553885588218
0xfc7b1daD...A19680760 77.931407688246677076 Eth77.959669688246677076 Eth0.028262

Execution Trace

ETH 0.028262 AggregationRouterV3.swap( caller=0x27239549DD40E1D60F5B80B0C4196923745B1FD2, desc=[{name:srcToken, type:address, order:1, indexed:false, value:0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, valueString:0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE}, {name:dstToken, type:address, order:2, indexed:false, value:0x6B175474E89094C44Da98b954EedeAC495271d0F, valueString:0x6B175474E89094C44Da98b954EedeAC495271d0F}, {name:srcReceiver, type:address, order:3, indexed:false, value:0x27239549DD40E1D60F5B80B0C4196923745B1FD2, valueString:0x27239549DD40E1D60F5B80B0C4196923745B1FD2}, {name:dstReceiver, type:address, order:4, indexed:false, value:0x9Ff7A776A46a53a70D941Dc0b11510dea6C04EE4, valueString:0x9Ff7A776A46a53a70D941Dc0b11510dea6C04EE4}, {name:amount, type:uint256, order:5, indexed:false, value:28262000000000000, valueString:28262000000000000}, {name:minReturnAmount, type:uint256, order:6, indexed:false, value:130540923167200004014, valueString:130540923167200004014}, {name:flags, type:uint256, order:7, indexed:false, value:0, valueString:0}, {name:permit, type:bytes, order:8, indexed:false, value:0x, valueString:0x}], data=0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000300800000000000000000000000A18607CA4A3804CC3CD5730EAFEFCC47A7641643000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000646823A6A4600000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000204BA93C39C000000000000000000000000FC7B1DAD07111C77C5D619043D75AC9A1968076000000000000000000000000027239549DD40E1D60F5B80B0C4196923745B1FD200000000000000000000000000000000000000000000000000000000000000000000000000000000000000006B175474E89094C44DA98B954EEDEAC495271D0F00000000000000000000000000000000000000000000000000646823A6A4600000000000000000000000000000000000000000000000000000646823A6A4600000000000000000000000000000000000000000000000000737CE0AA27919B3000000000000000000000000000000000000000000000000000000000000CF28220000000000000000000000000000000000000000000000000000017CFFDDC06A000000000000000000000000000000000000000000000000000000000000000202D7D917FE02447571DB7BD0EA4401DC6844BE52695F7BF8B4E1D8ABD8C4EA4800000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000041CD814DD23620384540148E2219238267B8EA30AC8B34BB1B9E0A4A3379C226356D4AEC8227860C413322E97237DD4827CA978F2714DF69EE4BF03321699EA8F81C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000184B3AF37C0000000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000000000000000000000000000000000240000000000000000000000006B175474E89094C44DA98B954EEDEAC495271D0F00000000000000000000000000000001000000000000000000000000000000010000000000000000000000006B175474E89094C44DA98B954EEDEAC495271D0F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000044A9059CBB0000000000000000000000009FF7A776A46A53A70D941DC0B11510DEA6C04EE400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ) => ( returnAmount=133148371726188000000, gasLeft=78654 )
  • Dai.balanceOf( 0x9Ff7A776A46a53a70D941Dc0b11510dea6C04EE4 ) => ( 0 )
  • ETH 0.028262 0x27239549dd40e1d60f5b80b0c4196923745b1fd2.d9c45357( )
    • ETH 0.028262 0xa18607ca4a3804cc3cd5730eafefcc47a7641643.ba93c39c( )
      • ETH 0.028262 0xfc7b1dad07111c77c5d619043d75ac9a19680760.ecc0661a( )
        • ETH 0.028262 0x20ef25713c37855fbb8ed483efddff9407442650.ecc0661a( )
          • Null: 0x000...001.da31a9fb( )
          • Dai.transfer( dst=0x27239549DD40E1D60F5B80B0C4196923745B1FD2, wad=133148371726188000000 ) => ( True )
          • 0x27239549dd40e1d60f5b80b0c4196923745b1fd2.b3af37c0( )
            • Dai.balanceOf( 0x27239549DD40E1D60F5B80B0C4196923745B1FD2 ) => ( 133148371726188000000 )
            • Dai.transfer( dst=0x9Ff7A776A46a53a70D941Dc0b11510dea6C04EE4, wad=133148371726188000000 ) => ( True )
            • Dai.balanceOf( 0x9Ff7A776A46a53a70D941Dc0b11510dea6C04EE4 ) => ( 133148371726188000000 )
              File 1 of 2: AggregationRouterV3
              /*
                                                                         ,▄▓▓██▌   ,╓▄▄▓▓▓▓▓▓▓▓▄▄▄,,                          
                                                                      ,▓██▓███▓▄▓███▓╬╬╬╬╬╬╬╬╬╬╬╬╬▓███▓▄,                     
                                                                ▄█   ▓██╬╣███████╬▓▀╬╬▓▓▓████████████▓█████▄,                 
                                                               ▓██▌ ▓██╬╣██████╬▓▌  ██████████████████████▌╙╙▀ⁿ
                                                              ▐████████╬▓████▓▓█╨ ▄ ╟█████████▓▓╬╬╬╬╬▓▓█████▓▄
                                                └▀▓▓▄╓        ╟█▓╣█████▓██████▀ ╓█▌ ███████▓▓▓▓▓╬╬╬╬╬╬╬╬╬╬╬╬▓██▓▄
                                                   └▀████▓▄╥  ▐██╬╬██████████╙ Æ▀─ ▓███▀╚╠╬╩▀▀███████▓▓╬╬╬╬╬╬╬╬╬██▄
                                                      └▀██▓▀▀█████▓╬▓██████▀     ▄█████▒╠"      └╙▓██████▓╬╬╬╬╬╬╬╬██▄
                                                         └▀██▄,└╙▀▀████▌└╙    ^"▀╙╙╙"╙██      @▄    ╙▀███████╬╬╬╬╬╬╬██µ
                                                            └▀██▓▄, ██▌       ╒       ╙█▓     ]▓█▓╔    ▀███████▓╬╬╬╬╬▓█▌
                                                                ▀█████       ▓         ╟█▌    ]╠██▓░▒╓   ▀████████╬╬╬╬╣█▌
                                                                ▐████      ╓█▀█▌      ,██▌    ╚Å███▓▒▒╠╓  ╙█████████╬╬╬╣█▌
                                                                └████     ▓█░░▓█      ▀▀▀    φ▒╫████▒▒▒▒╠╓  █████████▓╬╬▓█µ
                                                                 ╘███µ ▌▄█▓▄▓▀`     ,▀    ,╔╠░▓██████▌╠▒▒▒φ  ██████████╬╬██
                                                                 ▐████µ╙▓▀`     ,▀╙,╔╔φφφ╠░▄▓███████▌░▓╙▒▒▒╠ └██╬███████╬▓█⌐
                                                                 ╫██ ▓▌         ▌φ▒▒░▓██████████████▌▒░▓╚▒▒▒╠ ▓██╬▓██████╣█▌
                                                                 ██▌           ▌╔▒▒▄████████████████▒▒▒░▌╠▒▒▒≥▐██▓╬╬███████▌
                                                                 ██▌      ,╓φ╠▓«▒▒▓████▀  ▀█████████▌▒▒▒╟░▒▒▒▒▐███╬╬╣████▓█▌
                                                                ▐██      ╠▒▄▓▓███▓████└     ▀████████▌▒▒░▌╚▒▒▒▐███▓╬╬████ ╙▌
                                                                ███  )  ╠▒░░░▒░╬████▀        └████████░▒▒░╬∩▒▒▓████╬╬╣███
                                                               ▓██    ╠╠▒▒▐█▀▀▌`░╫██           ███████▒▒▒▒░▒▒½█████╬╬╣███
                                                              ███ ,█▄ ╠▒▒▒╫▌,▄▀,▒╫██           ╟██████▒▒▒░╣⌠▒▓█████╬╬╣██▌
                                                             ╘██µ ██` ╠▒▒░██╬φ╠▄▓██`            ██████░░▌φ╠░▓█████▓╬╬▓██
                                                              ╟██  .φ╠▒░▄█▀░░▄██▀└              █████▌▒╣φ▒░▓██████╬╬╣██
                                                               ▀██▄▄▄╓▄███████▀                ▐█████░▓φ▒▄███████▓╬╣██
                                                                 ╙▀▀▀██▀└                      ████▓▄▀φ▄▓████████╬▓█▀
                                                                                              ▓███╬╩╔╣██████████▓██└
                                                                                            ╓████▀▄▓████████▀████▀
                                                                                          ,▓███████████████─]██╙
                                                                                       ,▄▓██████████████▀└  ╙
                                                                                  ,╓▄▓███████████████▀╙
                                                                           `"▀▀▀████████▀▀▀▀`▄███▀▀└
                                                                                            └└
                                              
                                  
              
                                  11\   11\                     11\             11\   11\            11\                                       11\       
                                1111 |  \__|                    11 |            111\  11 |           11 |                                      11 |      
                                \_11 |  11\ 1111111\   1111111\ 1111111\        1111\ 11 | 111111\ 111111\   11\  11\  11\  111111\   111111\  11 |  11\ 
                                  11 |  11 |11  __11\ 11  _____|11  __11\       11 11\11 |11  __11\\_11  _|  11 | 11 | 11 |11  __11\ 11  __11\ 11 | 11  |
                                  11 |  11 |11 |  11 |11 /      11 |  11 |      11 \1111 |11111111 | 11 |    11 | 11 | 11 |11 /  11 |11 |  \__|111111  / 
                                  11 |  11 |11 |  11 |11 |      11 |  11 |      11 |\111 |11   ____| 11 |11\ 11 | 11 | 11 |11 |  11 |11 |      11  _11<  
                                111111\ 11 |11 |  11 |\1111111\ 11 |  11 |      11 | \11 |\1111111\  \1111  |\11111\1111  |\111111  |11 |      11 | \11\ 
                                \______|\__|\__|  \__| \_______|\__|  \__|      \__|  \__| \_______|  \____/  \_____\____/  \______/ \__|      \__|  \__|
                                                                                                                                                         
                                                                                                                                                         
                                                                                                                                                         
                                             111111\                                                               11\     11\                           
                                            11  __11\                                                              11 |    \__|                          
                                            11 /  11 | 111111\   111111\   111111\   111111\   111111\   111111\ 111111\   11\  111111\  1111111\        
                                            11111111 |11  __11\ 11  __11\ 11  __11\ 11  __11\ 11  __11\  \____11\\_11  _|  11 |11  __11\ 11  __11\       
                                            11  __11 |11 /  11 |11 /  11 |11 |  \__|11111111 |11 /  11 | 1111111 | 11 |    11 |11 /  11 |11 |  11 |      
                                            11 |  11 |11 |  11 |11 |  11 |11 |      11   ____|11 |  11 |11  __11 | 11 |11\ 11 |11 |  11 |11 |  11 |      
                                            11 |  11 |\1111111 |\1111111 |11 |      \1111111\ \1111111 |\1111111 | \1111  |11 |\111111  |11 |  11 |      
                                            \__|  \__| \____11 | \____11 |\__|       \_______| \____11 | \_______|  \____/ \__| \______/ \__|  \__|      
                                                      11\   11 |11\   11 |                    11\   11 |                                                 
                                                      \111111  |\111111  |                    \111111  |                                                 
                                                       \______/  \______/                      \______/                                                  
                                                              1111111\                        11\                                                        
                                                              11  __11\                       11 |                                                       
                                                              11 |  11 | 111111\  11\   11\ 111111\    111111\   111111\                                 
                                                              1111111  |11  __11\ 11 |  11 |\_11  _|  11  __11\ 11  __11\                                
                                                              11  __11< 11 /  11 |11 |  11 |  11 |    11111111 |11 |  \__|                               
                                                              11 |  11 |11 |  11 |11 |  11 |  11 |11\ 11   ____|11 |                                     
                                                              11 |  11 |\111111  |\111111  |  \1111  |\1111111\ 11 |                                     
                                                              \__|  \__| \______/  \______/    \____/  \_______|\__|                                     
              */
              
              // File @openzeppelin/contracts/utils/Context.sol@v3.4.1
              
              // SPDX-License-Identifier: MIT
              
              pragma solidity >=0.6.0 <0.8.0;
              
              /*
               * @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 GSN 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 payable) {
                      return msg.sender;
                  }
              
                  function _msgData() internal view virtual returns (bytes memory) {
                      this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                      return msg.data;
                  }
              }
              
              
              // File @openzeppelin/contracts/access/Ownable.sol@v3.4.1
              
              
              
              pragma solidity >=0.6.0 <0.8.0;
              
              /**
               * @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.
               *
               * By default, the owner account will be the one that deploys the contract. 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;
              
                  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              
                  /**
                   * @dev Initializes the contract setting the deployer as the initial owner.
                   */
                  constructor () internal {
                      address msgSender = _msgSender();
                      _owner = msgSender;
                      emit OwnershipTransferred(address(0), msgSender);
                  }
              
                  /**
                   * @dev Returns the address of the current owner.
                   */
                  function owner() public view virtual returns (address) {
                      return _owner;
                  }
              
                  /**
                   * @dev Throws if called by any account other than the owner.
                   */
                  modifier onlyOwner() {
                      require(owner() == _msgSender(), "Ownable: caller is not the owner");
                      _;
                  }
              
                  /**
                   * @dev Leaves the contract without owner. It will not be possible to call
                   * `onlyOwner` functions anymore. Can only be called by the current owner.
                   *
                   * NOTE: Renouncing ownership will leave the contract without an owner,
                   * thereby removing any functionality that is only available to the owner.
                   */
                  function renounceOwnership() public virtual onlyOwner {
                      emit OwnershipTransferred(_owner, address(0));
                      _owner = 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 {
                      require(newOwner != address(0), "Ownable: new owner is the zero address");
                      emit OwnershipTransferred(_owner, newOwner);
                      _owner = newOwner;
                  }
              }
              
              
              // File @openzeppelin/contracts/token/ERC20/IERC20.sol@v3.4.1
              
              
              
              pragma solidity >=0.6.0 <0.8.0;
              
              /**
               * @dev Interface of the ERC20 standard as defined in the EIP.
               */
              interface IERC20 {
                  /**
                   * @dev Returns the amount of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
              
                  /**
                   * @dev Returns the amount of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
              
                  /**
                   * @dev Moves `amount` tokens from the caller's account to `recipient`.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transfer(address recipient, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Returns the remaining number of tokens that `spender` will be
                   * allowed to spend on behalf of `owner` through {transferFrom}. This is
                   * zero by default.
                   *
                   * This value changes when {approve} or {transferFrom} are called.
                   */
                  function allowance(address owner, address spender) external view returns (uint256);
              
                  /**
                   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * IMPORTANT: Beware that changing an allowance with this method brings the risk
                   * that someone may use both the old and the new allowance by unfortunate
                   * transaction ordering. One possible solution to mitigate this race
                   * condition is to first reduce the spender's allowance to 0 and set the
                   * desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   *
                   * Emits an {Approval} event.
                   */
                  function approve(address spender, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Moves `amount` tokens from `sender` to `recipient` using the
                   * allowance mechanism. `amount` is then deducted from the caller's
                   * allowance.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Emitted when `value` tokens are moved from one account (`from`) to
                   * another (`to`).
                   *
                   * Note that `value` may be zero.
                   */
                  event Transfer(address indexed from, address indexed to, uint256 value);
              
                  /**
                   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                   * a call to {approve}. `value` is the new allowance.
                   */
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              
              
              // File @openzeppelin/contracts/math/SafeMath.sol@v3.4.1
              
              
              
              pragma solidity >=0.6.0 <0.8.0;
              
              /**
               * @dev Wrappers over Solidity's arithmetic operations with added overflow
               * checks.
               *
               * Arithmetic operations in Solidity wrap on overflow. This can easily result
               * in bugs, because programmers usually assume that an overflow raises an
               * error, which is the standard behavior in high level programming languages.
               * `SafeMath` restores this intuition by reverting the transaction when an
               * operation overflows.
               *
               * Using this library instead of the unchecked operations eliminates an entire
               * class of bugs, so it's recommended to use it always.
               */
              library SafeMath {
                  /**
                   * @dev Returns the addition of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      uint256 c = a + b;
                      if (c < a) return (false, 0);
                      return (true, c);
                  }
              
                  /**
                   * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b > a) return (false, 0);
                      return (true, a - b);
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                      if (a == 0) return (true, 0);
                      uint256 c = a * b;
                      if (c / a != b) return (false, 0);
                      return (true, c);
                  }
              
                  /**
                   * @dev Returns the division of two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b == 0) return (false, 0);
                      return (true, a / b);
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b == 0) return (false, 0);
                      return (true, a % b);
                  }
              
                  /**
                   * @dev Returns the addition of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `+` operator.
                   *
                   * Requirements:
                   *
                   * - Addition cannot overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a, "SafeMath: addition overflow");
                      return c;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting on
                   * overflow (when the result is negative).
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a, "SafeMath: subtraction overflow");
                      return a - b;
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `*` operator.
                   *
                   * Requirements:
                   *
                   * - Multiplication cannot overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      if (a == 0) return 0;
                      uint256 c = a * b;
                      require(c / a == b, "SafeMath: multiplication overflow");
                      return c;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting on
                   * division by zero. The result is rounded towards zero.
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0, "SafeMath: division by zero");
                      return a / b;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting when dividing by zero.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0, "SafeMath: modulo by zero");
                      return a % b;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                   * overflow (when the result is negative).
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {trySub}.
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b <= a, errorMessage);
                      return a - b;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                   * division by zero. The result is rounded towards zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryDiv}.
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b > 0, errorMessage);
                      return a / b;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting with custom message when dividing by zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryMod}.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b > 0, errorMessage);
                      return a % b;
                  }
              }
              
              
              // File @openzeppelin/contracts/utils/Address.sol@v3.4.1
              
              
              
              pragma solidity >=0.6.2 <0.8.0;
              
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev Returns true if `account` is a contract.
                   *
                   * [IMPORTANT]
                   * ====
                   * It is unsafe to assume that an address for which this function returns
                   * false is an externally-owned account (EOA) and not a contract.
                   *
                   * Among others, `isContract` will return false for the following
                   * types of addresses:
                   *
                   *  - an externally-owned account
                   *  - a contract in construction
                   *  - an address where a contract will be created
                   *  - an address where a contract lived, but was destroyed
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies on extcodesize, which returns 0 for contracts in
                      // construction, since the code is only stored at the end of the
                      // constructor execution.
              
                      uint256 size;
                      // solhint-disable-next-line no-inline-assembly
                      assembly { size := extcodesize(account) }
                      return size > 0;
                  }
              
                  /**
                   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                   * `recipient`, forwarding all available gas and reverting on errors.
                   *
                   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                   * of certain opcodes, possibly making contracts go over the 2300 gas limit
                   * imposed by `transfer`, making them unable to receive funds via
                   * `transfer`. {sendValue} removes this limitation.
                   *
                   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                   *
                   * IMPORTANT: because control is transferred to `recipient`, care must be
                   * taken to not create reentrancy vulnerabilities. Consider using
                   * {ReentrancyGuard} or the
                   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      require(address(this).balance >= amount, "Address: insufficient balance");
              
                      // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                      (bool success, ) = recipient.call{ value: amount }("");
                      require(success, "Address: unable to send value, recipient may have reverted");
                  }
              
                  /**
                   * @dev Performs a Solidity function call using a low level `call`. A
                   * plain`call` is an unsafe replacement for a function call: use this
                   * function instead.
                   *
                   * If `target` reverts with a revert reason, it is bubbled up by this
                   * function (like regular Solidity function calls).
                   *
                   * Returns the raw returned data. To convert to the expected return value,
                   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                   *
                   * Requirements:
                   *
                   * - `target` must be a contract.
                   * - calling `target` with `data` must not revert.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                   * `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but also transferring `value` wei to `target`.
                   *
                   * Requirements:
                   *
                   * - the calling contract must have an ETH balance of at least `value`.
                   * - the called Solidity function must be `payable`.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                   * with `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                      require(address(this).balance >= value, "Address: insufficient balance for call");
                      require(isContract(target), "Address: call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.call{ value: value }(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      return functionStaticCall(target, data, "Address: low-level static call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                      require(isContract(target), "Address: static call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      require(isContract(target), "Address: delegate call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                      if (success) {
                          return returndata;
                      } else {
                          // Look for revert reason and bubble it up if present
                          if (returndata.length > 0) {
                              // The easiest way to bubble the revert reason is using memory via assembly
              
                              // solhint-disable-next-line no-inline-assembly
                              assembly {
                                  let returndata_size := mload(returndata)
                                  revert(add(32, returndata), returndata_size)
                              }
                          } else {
                              revert(errorMessage);
                          }
                      }
                  }
              }
              
              
              // File @openzeppelin/contracts/token/ERC20/SafeERC20.sol@v3.4.1
              
              
              
              pragma solidity >=0.6.0 <0.8.0;
              
              
              
              /**
               * @title SafeERC20
               * @dev Wrappers around ERC20 operations that throw on failure (when the token
               * contract returns false). Tokens that return no value (and instead revert or
               * throw on failure) are also supported, non-reverting calls are assumed to be
               * successful.
               * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
               * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
               */
              library SafeERC20 {
                  using SafeMath for uint256;
                  using Address for address;
              
                  function safeTransfer(IERC20 token, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                  }
              
                  function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                  }
              
                  /**
                   * @dev Deprecated. This function has issues similar to the ones found in
                   * {IERC20-approve}, and its usage is discouraged.
                   *
                   * Whenever possible, use {safeIncreaseAllowance} and
                   * {safeDecreaseAllowance} instead.
                   */
                  function safeApprove(IERC20 token, address spender, uint256 value) internal {
                      // safeApprove should only be called when setting an initial allowance,
                      // or when resetting it to zero. To increase and decrease it, use
                      // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                      // solhint-disable-next-line max-line-length
                      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 safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).add(value);
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              
                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              
                  /**
                   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                   * on the return value: the return value is optional (but if data is returned, it must not be false).
                   * @param token The token targeted by the call.
                   * @param data The call data (encoded using abi.encode or one of its variants).
                   */
                  function _callOptionalReturn(IERC20 token, bytes memory data) private {
                      // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                      // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                      // the target address contains contract code and also asserts for success in the low-level call.
              
                      bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                      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");
                      }
                  }
              }
              
              
              // File contracts/helpers/UniERC20.sol
              
              
              
              pragma solidity ^0.6.12;
              
              
              library UniERC20 {
                  using SafeMath for uint256;
              
                  IERC20 private constant _ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
                  IERC20 private constant _ZERO_ADDRESS = IERC20(0);
              
                  function isETH(IERC20 token) internal pure returns (bool) {
                      return (token == _ZERO_ADDRESS || token == _ETH_ADDRESS);
                  }
              
                  function uniBalanceOf(IERC20 token, address account) internal view returns (uint256) {
                      if (isETH(token)) {
                          return account.balance;
                      } else {
                          return token.balanceOf(account);
                      }
                  }
              
                  function uniTransfer(IERC20 token, address payable to, uint256 amount) internal {
                      if (amount > 0) {
                          if (isETH(token)) {
                              to.transfer(amount);
                          } else {
                              _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, amount));
                          }
                      }
                  }
              
                  function uniApprove(IERC20 token, address to, uint256 amount) internal {
                      require(!isETH(token), "Approve called on ETH");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = address(token).call(abi.encodeWithSelector(token.approve.selector, to, amount));
              
                      if (!success || (returndata.length > 0 && !abi.decode(returndata, (bool)))) {
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, to, 0));
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, to, amount));
                      }
                  }
              
                  function _callOptionalReturn(IERC20 token, bytes memory data) private {
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = address(token).call(data);
                      require(success, "low-level call failed");
              
                      if (returndata.length > 0) { // Return data is optional
                          require(abi.decode(returndata, (bool)), "ERC20 operation did not succeed");
                      }
                  }
              }
              
              
              // File contracts/interfaces/IChi.sol
              
              
              
              pragma solidity ^0.6.12;
              
              interface IChi is IERC20 {
                  function mint(uint256 value) external;
                  function free(uint256 value) external returns (uint256 freed);
                  function freeFromUpTo(address from, uint256 value) external returns (uint256 freed);
              }
              
              
              // File contracts/interfaces/IGasDiscountExtension.sol
              
              
              
              pragma solidity ^0.6.12;
              
              interface IGasDiscountExtension {
                  function calculateGas(uint256 gasUsed, uint256 flags, uint256 calldataLength) external view returns (IChi, uint256);
              }
              
              
              // File contracts/interfaces/IAggregationExecutor.sol
              
              
              
              pragma solidity ^0.6.12;
              
              interface IAggregationExecutor is IGasDiscountExtension {
                  function callBytes(bytes calldata data) external payable;  // 0xd9c45357
              }
              
              
              // File contracts/helpers/RevertReasonParser.sol
              
              
              
              pragma solidity ^0.6.12;
              
              
              library RevertReasonParser {
                  function parse(bytes memory data, string memory prefix) internal pure returns (string memory) {
                      // https://solidity.readthedocs.io/en/latest/control-structures.html#revert
                      // We assume that revert reason is abi-encoded as Error(string)
              
                      // 68 = 4-byte selector 0x08c379a0 + 32 bytes offset + 32 bytes length
                      if (data.length >= 68 && data[0] == "\x08" && data[1] == "\xc3" && data[2] == "\x79" && data[3] == "\xa0") {
                          string memory reason;
                          // solhint-disable no-inline-assembly
                          assembly {
                              // 68 = 32 bytes data length + 4-byte selector + 32 bytes offset
                              reason := add(data, 68)
                          }
                          /*
                              revert reason is padded up to 32 bytes with ABI encoder: Error(string)
                              also sometimes there is extra 32 bytes of zeros padded in the end:
                              https://github.com/ethereum/solidity/issues/10170
                              because of that we can't check for equality and instead check
                              that string length + extra 68 bytes is less than overall data length
                          */
                          require(data.length >= 68 + bytes(reason).length, "Invalid revert reason");
                          return string(abi.encodePacked(prefix, "Error(", reason, ")"));
                      }
                      // 36 = 4-byte selector 0x4e487b71 + 32 bytes integer
                      else if (data.length == 36 && data[0] == "\x4e" && data[1] == "\x48" && data[2] == "\x7b" && data[3] == "\x71") {
                          uint256 code;
                          // solhint-disable no-inline-assembly
                          assembly {
                              // 36 = 32 bytes data length + 4-byte selector
                              code := mload(add(data, 36))
                          }
                          return string(abi.encodePacked(prefix, "Panic(", _toHex(code), ")"));
                      }
              
                      return string(abi.encodePacked(prefix, "Unknown(", _toHex(data), ")"));
                  }
              
                  function _toHex(uint256 value) private pure returns(string memory) {
                      return _toHex(abi.encodePacked(value));
                  }
              
                  function _toHex(bytes memory data) private pure returns(string memory) {
                      bytes16 alphabet = 0x30313233343536373839616263646566;
                      bytes memory str = new bytes(2 + data.length * 2);
                      str[0] = "0";
                      str[1] = "x";
                      for (uint256 i = 0; i < data.length; i++) {
                          str[2 * i + 2] = alphabet[uint8(data[i] >> 4)];
                          str[2 * i + 3] = alphabet[uint8(data[i] & 0x0f)];
                      }
                      return string(str);
                  }
              }
              
              
              // File contracts/interfaces/IERC20Permit.sol
              
              
              
              pragma solidity ^0.6.12;
              
              
              interface IERC20Permit {
                  function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
              }
              
              
              // File contracts/helpers/Permitable.sol
              
              
              
              pragma solidity ^0.6.12;
              
              
              
              contract Permitable {
                  event Error(
                      string reason
                  );
              
                  function _permit(IERC20 token, uint256 amount, bytes calldata permit) internal {
                      if (permit.length == 32 * 7) {
                          // solhint-disable-next-line avoid-low-level-calls
                          (bool success, bytes memory result) = address(token).call(abi.encodePacked(IERC20Permit.permit.selector, permit));
                          if (!success) {
                              string memory reason = RevertReasonParser.parse(result, "Permit call failed: ");
                              if (token.allowance(msg.sender, address(this)) < amount) {
                                  revert(reason);
                              } else {
                                  emit Error(reason);
                              }
                          }
                      }
                  }
              }
              
              
              // File contracts/UnoswapRouter.sol
              
              
              
              pragma solidity ^0.6.12;
              
              contract UnoswapRouter is Permitable {
                  uint256 private constant _TRANSFER_FROM_CALL_SELECTOR_32 = 0x23b872dd00000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _WETH_DEPOSIT_CALL_SELECTOR_32 = 0xd0e30db000000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _WETH_WITHDRAW_CALL_SELECTOR_32 = 0x2e1a7d4d00000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _ERC20_TRANSFER_CALL_SELECTOR_32 = 0xa9059cbb00000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _ADDRESS_MASK =   0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff;
                  uint256 private constant _REVERSE_MASK =   0x8000000000000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _WETH_MASK =      0x4000000000000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _NUMERATOR_MASK = 0x0000000000000000ffffffff0000000000000000000000000000000000000000;
                  uint256 private constant _WETH = 0x000000000000000000000000C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
                  uint256 private constant _UNISWAP_PAIR_RESERVES_CALL_SELECTOR_32 = 0x0902f1ac00000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _UNISWAP_PAIR_SWAP_CALL_SELECTOR_32 = 0x022c0d9f00000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _DENOMINATOR = 1000000000;
                  uint256 private constant _NUMERATOR_OFFSET = 160;
              
                  receive() external payable {
                      // solhint-disable-next-line avoid-tx-origin
                      require(msg.sender != tx.origin, "ETH deposit rejected");
                  }
              
                  function unoswapWithPermit(
                      IERC20 srcToken,
                      uint256 amount,
                      uint256 minReturn,
                      bytes32[] calldata pools,
                      bytes calldata permit
                  ) external payable returns(uint256 returnAmount) {
                      _permit(srcToken, amount, permit);
                      return unoswap(srcToken, amount, minReturn, pools);
                  }
              
                  function unoswap(
                      IERC20 srcToken,
                      uint256 amount,
                      uint256 minReturn,
                      bytes32[] calldata /* pools */
                  ) public payable returns(uint256 returnAmount) {
                      assembly {  // solhint-disable-line no-inline-assembly
                          function reRevert() {
                              returndatacopy(0, 0, returndatasize())
                              revert(0, returndatasize())
                          }
              
                          function revertWithReason(m, len) {
                              mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
                              mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
                              mstore(0x40, m)
                              revert(0, len)
                          }
              
                          function swap(emptyPtr, swapAmount, pair, reversed, numerator, dst) -> ret {
                              mstore(emptyPtr, _UNISWAP_PAIR_RESERVES_CALL_SELECTOR_32)
                              if iszero(staticcall(gas(), pair, emptyPtr, 0x4, emptyPtr, 0x40)) {
                                  reRevert()
                              }
              
                              let reserve0 := mload(emptyPtr)
                              let reserve1 := mload(add(emptyPtr, 0x20))
                              if reversed {
                                  let tmp := reserve0
                                  reserve0 := reserve1
                                  reserve1 := tmp
                              }
                              ret := mul(swapAmount, numerator)
                              ret := div(mul(ret, reserve1), add(ret, mul(reserve0, _DENOMINATOR)))
              
                              mstore(emptyPtr, _UNISWAP_PAIR_SWAP_CALL_SELECTOR_32)
                              switch reversed
                              case 0 {
                                  mstore(add(emptyPtr, 0x04), 0)
                                  mstore(add(emptyPtr, 0x24), ret)
                              }
                              default {
                                  mstore(add(emptyPtr, 0x04), ret)
                                  mstore(add(emptyPtr, 0x24), 0)
                              }
                              mstore(add(emptyPtr, 0x44), dst)
                              mstore(add(emptyPtr, 0x64), 0x80)
                              mstore(add(emptyPtr, 0x84), 0)
                              if iszero(call(gas(), pair, 0, emptyPtr, 0xa4, 0, 0)) {
                                  reRevert()
                              }
                          }
              
                          let emptyPtr := mload(0x40)
                          mstore(0x40, add(emptyPtr, 0xc0))
              
                          let poolsOffset := add(calldataload(0x64), 0x4)
                          let poolsEndOffset := calldataload(poolsOffset)
                          poolsOffset := add(poolsOffset, 0x20)
                          poolsEndOffset := add(poolsOffset, mul(0x20, poolsEndOffset))
                          let rawPair := calldataload(poolsOffset)
                          switch srcToken
                          case 0 {
                              if iszero(eq(amount, callvalue())) {
                                  revertWithReason(0x00000011696e76616c6964206d73672e76616c75650000000000000000000000, 0x55)  // "invalid msg.value"
                              }
              
                              mstore(emptyPtr, _WETH_DEPOSIT_CALL_SELECTOR_32)
                              if iszero(call(gas(), _WETH, amount, emptyPtr, 0x4, 0, 0)) {
                                  reRevert()
                              }
              
                              mstore(emptyPtr, _ERC20_TRANSFER_CALL_SELECTOR_32)
                              mstore(add(emptyPtr, 0x4), and(rawPair, _ADDRESS_MASK))
                              mstore(add(emptyPtr, 0x24), amount)
                              if iszero(call(gas(), _WETH, 0, emptyPtr, 0x44, 0, 0)) {
                                  reRevert()
                              }
                          }
                          default {
                              if callvalue() {
                                  revertWithReason(0x00000011696e76616c6964206d73672e76616c75650000000000000000000000, 0x55)  // "invalid msg.value"
                              }
              
                              mstore(emptyPtr, _TRANSFER_FROM_CALL_SELECTOR_32)
                              mstore(add(emptyPtr, 0x4), caller())
                              mstore(add(emptyPtr, 0x24), and(rawPair, _ADDRESS_MASK))
                              mstore(add(emptyPtr, 0x44), amount)
                              if iszero(call(gas(), srcToken, 0, emptyPtr, 0x64, 0, 0)) {
                                  reRevert()
                              }
                          }
              
                          returnAmount := amount
              
                          for {let i := add(poolsOffset, 0x20)} lt(i, poolsEndOffset) {i := add(i, 0x20)} {
                              let nextRawPair := calldataload(i)
              
                              returnAmount := swap(
                                  emptyPtr,
                                  returnAmount,
                                  and(rawPair, _ADDRESS_MASK),
                                  and(rawPair, _REVERSE_MASK),
                                  shr(_NUMERATOR_OFFSET, and(rawPair, _NUMERATOR_MASK)),
                                  and(nextRawPair, _ADDRESS_MASK)
                              )
              
                              rawPair := nextRawPair
                          }
              
                          switch and(rawPair, _WETH_MASK)
                          case 0 {
                              returnAmount := swap(
                                  emptyPtr,
                                  returnAmount,
                                  and(rawPair, _ADDRESS_MASK),
                                  and(rawPair, _REVERSE_MASK),
                                  shr(_NUMERATOR_OFFSET, and(rawPair, _NUMERATOR_MASK)),
                                  caller()
                              )
                          }
                          default {
                              returnAmount := swap(
                                  emptyPtr,
                                  returnAmount,
                                  and(rawPair, _ADDRESS_MASK),
                                  and(rawPair, _REVERSE_MASK),
                                  shr(_NUMERATOR_OFFSET, and(rawPair, _NUMERATOR_MASK)),
                                  address()
                              )
              
                              mstore(emptyPtr, _WETH_WITHDRAW_CALL_SELECTOR_32)
                              mstore(add(emptyPtr, 0x04), returnAmount)
                              if iszero(call(gas(), _WETH, 0, emptyPtr, 0x24, 0, 0)) {
                                  reRevert()
                              }
              
                              if iszero(call(gas(), caller(), returnAmount, 0, 0, 0, 0)) {
                                  reRevert()
                              }
                          }
              
                          if lt(returnAmount, minReturn) {
                              revertWithReason(0x000000164d696e2072657475726e206e6f742072656163686564000000000000, 0x5a)  // "Min return not reached"
                          }
                      }
                  }
              }
              
              
              // File contracts/AggregationRouterV3.sol
              
              
              
              pragma solidity ^0.6.12;
              pragma experimental ABIEncoderV2;
              
              
              
              
              
              
              contract AggregationRouterV3 is Ownable, UnoswapRouter {
                  using SafeMath for uint256;
                  using SafeERC20 for IERC20;
                  using UniERC20 for IERC20;
              
                  uint256 private constant _PARTIAL_FILL = 0x01;
                  uint256 private constant _REQUIRES_EXTRA_ETH = 0x02;
                  uint256 private constant _SHOULD_CLAIM = 0x04;
                  uint256 private constant _BURN_FROM_MSG_SENDER = 0x08;
                  uint256 private constant _BURN_FROM_TX_ORIGIN = 0x10;
              
                  struct SwapDescription {
                      IERC20 srcToken;
                      IERC20 dstToken;
                      address srcReceiver;
                      address dstReceiver;
                      uint256 amount;
                      uint256 minReturnAmount;
                      uint256 flags;
                      bytes permit;
                  }
              
                  event Swapped(
                      address sender,
                      IERC20 srcToken,
                      IERC20 dstToken,
                      address dstReceiver,
                      uint256 spentAmount,
                      uint256 returnAmount
                  );
              
                  function discountedSwap(
                      IAggregationExecutor caller,
                      SwapDescription calldata desc,
                      bytes calldata data
                  )
                      external
                      payable
                      returns (uint256 returnAmount, uint256 gasLeft, uint256 chiSpent)
                  {
                      uint256 initialGas = gasleft();
              
                      address chiSource = address(0);
                      if (desc.flags & _BURN_FROM_MSG_SENDER != 0) {
                          chiSource = msg.sender;
                      } else if (desc.flags & _BURN_FROM_TX_ORIGIN != 0) {
                          chiSource = tx.origin; // solhint-disable-line avoid-tx-origin
                      } else {
                          revert("Incorrect CHI burn flags");
                      }
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returnData) = address(this).delegatecall(abi.encodeWithSelector(this.swap.selector, caller, desc, data));
                      if (success) {
                          (returnAmount,) = abi.decode(returnData, (uint256, uint256));
                      } else {
                          if (msg.value > 0) {
                              msg.sender.transfer(msg.value);
                          }
                          emit Error(RevertReasonParser.parse(returnData, "Swap failed: "));
                      }
              
                      (IChi chi, uint256 amount) = caller.calculateGas(initialGas.sub(gasleft()), desc.flags, msg.data.length);
                      if (amount > 0) {
                          chiSpent = chi.freeFromUpTo(chiSource, amount);
                      }
                      gasLeft = gasleft();
                  }
              
                  function swap(
                      IAggregationExecutor caller,
                      SwapDescription calldata desc,
                      bytes calldata data
                  )
                      external
                      payable
                      returns (uint256 returnAmount, uint256 gasLeft)
                  {
                      require(desc.minReturnAmount > 0, "Min return should not be 0");
                      require(data.length > 0, "data should be not zero");
              
                      uint256 flags = desc.flags;
                      IERC20 srcToken = desc.srcToken;
                      IERC20 dstToken = desc.dstToken;
              
                      if (flags & _REQUIRES_EXTRA_ETH != 0) {
                          require(msg.value > (srcToken.isETH() ? desc.amount : 0), "Invalid msg.value");
                      } else {
                          require(msg.value == (srcToken.isETH() ? desc.amount : 0), "Invalid msg.value");
                      }
              
                      if (flags & _SHOULD_CLAIM != 0) {
                          require(!srcToken.isETH(), "Claim token is ETH");
                          _permit(srcToken, desc.amount, desc.permit);
                          srcToken.safeTransferFrom(msg.sender, desc.srcReceiver, desc.amount);
                      }
              
                      address dstReceiver = (desc.dstReceiver == address(0)) ? msg.sender : desc.dstReceiver;
                      uint256 initialSrcBalance = (flags & _PARTIAL_FILL != 0) ? srcToken.uniBalanceOf(msg.sender) : 0;
                      uint256 initialDstBalance = dstToken.uniBalanceOf(dstReceiver);
              
                      {
                          // solhint-disable-next-line avoid-low-level-calls
                          (bool success, bytes memory result) = address(caller).call{value: msg.value}(abi.encodePacked(caller.callBytes.selector, data));
                          if (!success) {
                              revert(RevertReasonParser.parse(result, "callBytes failed: "));
                          }
                      }
              
                      uint256 spentAmount = desc.amount;
                      returnAmount = dstToken.uniBalanceOf(dstReceiver).sub(initialDstBalance);
              
                      if (flags & _PARTIAL_FILL != 0) {
                          spentAmount = initialSrcBalance.add(desc.amount).sub(srcToken.uniBalanceOf(msg.sender));
                          require(returnAmount.mul(desc.amount) >= desc.minReturnAmount.mul(spentAmount), "Return amount is not enough");
                      } else {
                          require(returnAmount >= desc.minReturnAmount, "Return amount is not enough");
                      }
              
                      emit Swapped(
                          msg.sender,
                          srcToken,
                          dstToken,
                          dstReceiver,
                          spentAmount,
                          returnAmount
                      );
              
                      gasLeft = gasleft();
                  }
              
                  function rescueFunds(IERC20 token, uint256 amount) external onlyOwner {
                      token.uniTransfer(msg.sender, amount);
                  }
              
                  function destroy() external onlyOwner {
                      selfdestruct(msg.sender);
                  }
              }

              File 2 of 2: Dai
              // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol
              pragma solidity =0.5.12;
              
              ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol
              // 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; */
              
              contract LibNote {
                  event LogNote(
                      bytes4   indexed  sig,
                      address  indexed  usr,
                      bytes32  indexed  arg1,
                      bytes32  indexed  arg2,
                      bytes             data
                  ) anonymous;
              
                  modifier note {
                      _;
                      assembly {
                          // log an 'anonymous' event with a constant 6 words of calldata
                          // and four indexed topics: selector, caller, arg1 and arg2
                          let mark := msize                         // end of memory ensures zero
                          mstore(0x40, add(mark, 288))              // update free memory pointer
                          mstore(mark, 0x20)                        // bytes type data offset
                          mstore(add(mark, 0x20), 224)              // bytes size (padded)
                          calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
                          log4(mark, 288,                           // calldata
                               shl(224, shr(224, calldataload(0))), // msg.sig
                               caller,                              // msg.sender
                               calldataload(4),                     // arg1
                               calldataload(36)                     // arg2
                              )
                      }
                  }
              }
              
              ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol
              // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico
              
              // This program is free software: you can redistribute it and/or modify
              // it under the terms of the GNU Affero 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 Affero General Public License for more details.
              //
              // You should have received a copy of the GNU Affero General Public License
              // along with this program.  If not, see <https://www.gnu.org/licenses/>.
              
              /* pragma solidity 0.5.12; */
              
              /* import "./lib.sol"; */
              
              contract Dai is LibNote {
                  // --- Auth ---
                  mapping (address => uint) public wards;
                  function rely(address guy) external note auth { wards[guy] = 1; }
                  function deny(address guy) external note auth { wards[guy] = 0; }
                  modifier auth {
                      require(wards[msg.sender] == 1, "Dai/not-authorized");
                      _;
                  }
              
                  // --- ERC20 Data ---
                  string  public constant name     = "Dai Stablecoin";
                  string  public constant symbol   = "DAI";
                  string  public constant version  = "1";
                  uint8   public constant decimals = 18;
                  uint256 public totalSupply;
              
                  mapping (address => uint)                      public balanceOf;
                  mapping (address => mapping (address => uint)) public allowance;
                  mapping (address => uint)                      public nonces;
              
                  event Approval(address indexed src, address indexed guy, uint wad);
                  event Transfer(address indexed src, address indexed dst, uint wad);
              
                  // --- Math ---
                  function add(uint x, uint y) internal pure returns (uint z) {
                      require((z = x + y) >= x);
                  }
                  function sub(uint x, uint y) internal pure returns (uint z) {
                      require((z = x - y) <= x);
                  }
              
                  // --- EIP712 niceties ---
                  bytes32 public DOMAIN_SEPARATOR;
                  // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)");
                  bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;
              
                  constructor(uint256 chainId_) public {
                      wards[msg.sender] = 1;
                      DOMAIN_SEPARATOR = keccak256(abi.encode(
                          keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                          keccak256(bytes(name)),
                          keccak256(bytes(version)),
                          chainId_,
                          address(this)
                      ));
                  }
              
                  // --- Token ---
                  function transfer(address dst, uint wad) external returns (bool) {
                      return transferFrom(msg.sender, dst, wad);
                  }
                  function transferFrom(address src, address dst, uint wad)
                      public returns (bool)
                  {
                      require(balanceOf[src] >= wad, "Dai/insufficient-balance");
                      if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
                          require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance");
                          allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
                      }
                      balanceOf[src] = sub(balanceOf[src], wad);
                      balanceOf[dst] = add(balanceOf[dst], wad);
                      emit Transfer(src, dst, wad);
                      return true;
                  }
                  function mint(address usr, uint wad) external auth {
                      balanceOf[usr] = add(balanceOf[usr], wad);
                      totalSupply    = add(totalSupply, wad);
                      emit Transfer(address(0), usr, wad);
                  }
                  function burn(address usr, uint wad) external {
                      require(balanceOf[usr] >= wad, "Dai/insufficient-balance");
                      if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) {
                          require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance");
                          allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad);
                      }
                      balanceOf[usr] = sub(balanceOf[usr], wad);
                      totalSupply    = sub(totalSupply, wad);
                      emit Transfer(usr, address(0), wad);
                  }
                  function approve(address usr, uint wad) external returns (bool) {
                      allowance[msg.sender][usr] = wad;
                      emit Approval(msg.sender, usr, wad);
                      return true;
                  }
              
                  // --- Alias ---
                  function push(address usr, uint wad) external {
                      transferFrom(msg.sender, usr, wad);
                  }
                  function pull(address usr, uint wad) external {
                      transferFrom(usr, msg.sender, wad);
                  }
                  function move(address src, address dst, uint wad) external {
                      transferFrom(src, dst, wad);
                  }
              
                  // --- Approve by signature ---
                  function permit(address holder, address spender, uint256 nonce, uint256 expiry,
                                  bool allowed, uint8 v, bytes32 r, bytes32 s) external
                  {
                      bytes32 digest =
                          keccak256(abi.encodePacked(
                              "\x19\x01",
                              DOMAIN_SEPARATOR,
                              keccak256(abi.encode(PERMIT_TYPEHASH,
                                                   holder,
                                                   spender,
                                                   nonce,
                                                   expiry,
                                                   allowed))
                      ));
              
                      require(holder != address(0), "Dai/invalid-address-0");
                      require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit");
                      require(expiry == 0 || now <= expiry, "Dai/permit-expired");
                      require(nonce == nonces[holder]++, "Dai/invalid-nonce");
                      uint wad = allowed ? uint(-1) : 0;
                      allowance[holder][spender] = wad;
                      emit Approval(holder, spender, wad);
                  }
              }