ETH Price: $2,911.29 (-4.14%)
Gas: 4 Gwei

Transaction Decoder

Block:
16608528 at Feb-11-2023 10:32:59 PM +UTC
Transaction Fee:
0.0032971188864447 ETH $9.60
Gas Used:
174,212 Gas / 18.925899975 Gwei

Emitted Events:

108 DSProxy.0x1cff79cd00000000000000000000000000000000000000000000000000000000( 0x1cff79cd00000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000629e7da20197a5429d30da36e77d06cdf796b71a, 0x00000000000000000000000082ecd135dce65fbc6dbdd0e4237e0af93ffd5038, 0x0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 000000000000000000000000000000000000000000000000000001241cff79cd, 00000000000000000000000082ecd135dce65fbc6dbdd0e4237e0af93ffd5038, 0000000000000000000000000000000000000000000000000000000000000040, 00000000000000000000000000000000000000000000000000000000000000a4, 3e29e5650000000000000000000000005ef30b9986345249bc32d8928b7ee64d, e9435e39000000000000000000000000248ccbf4864221fc0e840f29bb042ad5, bfc89b5c00000000000000000000000000000000000000000000000000000000, 000075940000000000000000000000000000000000000000000001dc906756cf, bab4800000000000000000000000000000000000000000000000000000000000, 0000000100000000000000000000000000000000000000000000000000000000 )
109 WstETH.Transfer( from=[Sender] 0x629e7da20197a5429d30da36e77d06cdf796b71a, to=[Receiver] DSProxy, value=8791055560000000000000 )
110 WstETH.Approval( owner=[Sender] 0x629e7da20197a5429d30da36e77d06cdf796b71a, spender=[Receiver] DSProxy, value=0 )
111 WstETH.Approval( owner=[Receiver] DSProxy, spender=GemJoin, value=8791055560000000000000 )
112 Vat.0x7cdd3fde00000000000000000000000000000000000000000000000000000000( 0x7cdd3fde00000000000000000000000000000000000000000000000000000000, 0x5753544554482d42000000000000000000000000000000000000000000000000, 0x0000000000000000000000004288382dd4e559dc79dc62595ff27251c7c7a2f2, 0x0000000000000000000000000000000000000000000001dc906756cfbab48000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 7cdd3fde5753544554482d420000000000000000000000000000000000000000, 000000000000000000000000000000004288382dd4e559dc79dc62595ff27251, c7c7a2f20000000000000000000000000000000000000000000001dc906756cf, bab4800000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
113 WstETH.Transfer( from=[Receiver] DSProxy, to=GemJoin, value=8791055560000000000000 )
114 WstETH.Approval( owner=[Receiver] DSProxy, spender=GemJoin, value=0 )
115 GemJoin.0x3b4da69f00000000000000000000000000000000000000000000000000000000( 0x3b4da69f00000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004288382dd4e559dc79dc62595ff27251c7c7a2f2, 0x0000000000000000000000004288382dd4e559dc79dc62595ff27251c7c7a2f2, 0x0000000000000000000000000000000000000000000001dc906756cfbab48000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 3b4da69f0000000000000000000000004288382dd4e559dc79dc62595ff27251, c7c7a2f20000000000000000000000000000000000000000000001dc906756cf, bab4800000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
116 Vat.0x7608870300000000000000000000000000000000000000000000000000000000( 0x7608870300000000000000000000000000000000000000000000000000000000, 0x5753544554482d42000000000000000000000000000000000000000000000000, 0x000000000000000000000000ce2f7d7c40f8a04f43d645ddde9aba9c47434d4c, 0x0000000000000000000000004288382dd4e559dc79dc62595ff27251c7c7a2f2, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 760887035753544554482d420000000000000000000000000000000000000000, 00000000000000000000000000000000ce2f7d7c40f8a04f43d645ddde9aba9c, 47434d4c0000000000000000000000004288382dd4e559dc79dc62595ff27251, c7c7a2f20000000000000000000000004288382dd4e559dc79dc62595ff27251, c7c7a2f20000000000000000000000000000000000000000000001dc906756cf, bab4800000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x35D1b3F3...259A0492B
(Maker: MCD Vat)
0x629e7Da2...dF796b71A
(Wormhole Network Exploiter)
4.991173568832274663 Eth
Nonce: 56
4.987876449945829963 Eth
Nonce: 57
0.0032971188864447
(builder0x69)
1.927395305084356568 Eth1.927743729084356568 Eth0.000348424
0x7f39C581...c935E2Ca0

Execution Trace

DSProxy.execute( _target=0x82ecD135Dce65Fbc6DbdD0e4237E0AF93FFD5038, _data=0x3E29E5650000000000000000000000005EF30B9986345249BC32D8928B7EE64DE9435E39000000000000000000000000248CCBF4864221FC0E840F29BB042AD5BFC89B5C00000000000000000000000000000000000000000000000000000000000075940000000000000000000000000000000000000000000001DC906756CFBAB480000000000000000000000000000000000000000000000000000000000000000001 ) => ( response=0000000000000000000000000000000000000000000000000000000000000000 )
  • DssProxyActions.lockGem( manager=0x5ef30b9986345249bc32d8928B7ee64DE9435E39, gemJoin=0x248cCBf4864221fC0E840F29BB042ad5bFC89B5c, cdp=30100, wad=8791055560000000000000, transferFrom=True )
    • GemJoin.CALL( )
    • WstETH.transferFrom( sender=0x629e7Da20197a5429d30da36E77d06CdF796b71A, recipient=0x4288382dD4e559Dc79DC62595FF27251C7C7a2F2, amount=8791055560000000000000 ) => ( True )
    • GemJoin.CALL( )
    • WstETH.approve( spender=0x248cCBf4864221fC0E840F29BB042ad5bFC89B5c, amount=8791055560000000000000 ) => ( True )
    • GemJoin.join( usr=0x4288382dD4e559Dc79DC62595FF27251C7C7a2F2, wad=8791055560000000000000 )
      • Vat.slip( ilk=5753544554482D42000000000000000000000000000000000000000000000000, usr=0x4288382dD4e559Dc79DC62595FF27251C7C7a2F2, wad=8791055560000000000000 )
      • WstETH.transferFrom( sender=0x4288382dD4e559Dc79DC62595FF27251C7C7a2F2, recipient=0x248cCBf4864221fC0E840F29BB042ad5bFC89B5c, amount=8791055560000000000000 ) => ( True )
      • DssCdpManager.STATICCALL( )
      • DssCdpManager.ilks( 30100 ) => ( 5753544554482D42000000000000000000000000000000000000000000000000 )
      • DssCdpManager.urns( 30100 ) => ( 0xCe2f7d7C40f8A04f43d645ddDE9ABa9C47434d4c )
      • GemJoin.CALL( )
      • Vat.frob( i=5753544554482D42000000000000000000000000000000000000000000000000, u=0xCe2f7d7C40f8A04f43d645ddDE9ABa9C47434d4c, v=0x4288382dD4e559Dc79DC62595FF27251C7C7a2F2, w=0x4288382dD4e559Dc79DC62595FF27251C7C7a2F2, dink=8791055560000000000000, dart=0 )
        File 1 of 6: DSProxy
        // proxy.sol - execute actions atomically through the proxy's identity
        
        // Copyright (C) 2017  DappHub, LLC
        
        // 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.4.23;
        
        contract DSAuthority {
            function canCall(
                address src, address dst, bytes4 sig
            ) public view returns (bool);
        }
        
        contract DSAuthEvents {
            event LogSetAuthority (address indexed authority);
            event LogSetOwner     (address indexed owner);
        }
        
        contract DSAuth is DSAuthEvents {
            DSAuthority  public  authority;
            address      public  owner;
        
            constructor() public {
                owner = msg.sender;
                emit LogSetOwner(msg.sender);
            }
        
            function setOwner(address owner_)
                public
                auth
            {
                owner = owner_;
                emit LogSetOwner(owner);
            }
        
            function setAuthority(DSAuthority authority_)
                public
                auth
            {
                authority = authority_;
                emit LogSetAuthority(authority);
            }
        
            modifier auth {
                require(isAuthorized(msg.sender, msg.sig));
                _;
            }
        
            function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
                if (src == address(this)) {
                    return true;
                } else if (src == owner) {
                    return true;
                } else if (authority == DSAuthority(0)) {
                    return false;
                } else {
                    return authority.canCall(src, this, sig);
                }
            }
        }
        
        contract DSNote {
            event LogNote(
                bytes4   indexed  sig,
                address  indexed  guy,
                bytes32  indexed  foo,
                bytes32  indexed  bar,
                uint              wad,
                bytes             fax
            ) anonymous;
        
            modifier note {
                bytes32 foo;
                bytes32 bar;
        
                assembly {
                    foo := calldataload(4)
                    bar := calldataload(36)
                }
        
                emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
        
                _;
            }
        }
        
        // DSProxy
        // Allows code execution using a persistant identity This can be very
        // useful to execute a sequence of atomic actions. Since the owner of
        // the proxy can be changed, this allows for dynamic ownership models
        // i.e. a multisig
        contract DSProxy is DSAuth, DSNote {
            DSProxyCache public cache;  // global cache for contracts
        
            constructor(address _cacheAddr) public {
                require(setCache(_cacheAddr));
            }
        
            function() public payable {
            }
        
            // use the proxy to execute calldata _data on contract _code
            function execute(bytes _code, bytes _data)
                public
                payable
                returns (address target, bytes32 response)
            {
                target = cache.read(_code);
                if (target == 0x0) {
                    // deploy contract & store its address in cache
                    target = cache.write(_code);
                }
        
                response = execute(target, _data);
            }
        
            function execute(address _target, bytes _data)
                public
                auth
                note
                payable
                returns (bytes32 response)
            {
                require(_target != 0x0);
        
                // call contract in current context
                assembly {
                    let succeeded := delegatecall(sub(gas, 5000), _target, add(_data, 0x20), mload(_data), 0, 32)
                    response := mload(0)      // load delegatecall output
                    switch iszero(succeeded)
                    case 1 {
                        // throw if delegatecall failed
                        revert(0, 0)
                    }
                }
            }
        
            //set new cache
            function setCache(address _cacheAddr)
                public
                auth
                note
                returns (bool)
            {
                require(_cacheAddr != 0x0);        // invalid cache address
                cache = DSProxyCache(_cacheAddr);  // overwrite cache
                return true;
            }
        }
        
        // DSProxyFactory
        // This factory deploys new proxy instances through build()
        // Deployed proxy addresses are logged
        contract DSProxyFactory {
            event Created(address indexed sender, address indexed owner, address proxy, address cache);
            mapping(address=>bool) public isProxy;
            DSProxyCache public cache = new DSProxyCache();
        
            // deploys a new proxy instance
            // sets owner of proxy to caller
            function build() public returns (DSProxy proxy) {
                proxy = build(msg.sender);
            }
        
            // deploys a new proxy instance
            // sets custom owner of proxy
            function build(address owner) public returns (DSProxy proxy) {
                proxy = new DSProxy(cache);
                emit Created(msg.sender, owner, address(proxy), address(cache));
                proxy.setOwner(owner);
                isProxy[proxy] = true;
            }
        }
        
        // DSProxyCache
        // This global cache stores addresses of contracts previously deployed
        // by a proxy. This saves gas from repeat deployment of the same
        // contracts and eliminates blockchain bloat.
        
        // By default, all proxies deployed from the same factory store
        // contracts in the same cache. The cache a proxy instance uses can be
        // changed.  The cache uses the sha3 hash of a contract's bytecode to
        // lookup the address
        contract DSProxyCache {
            mapping(bytes32 => address) cache;
        
            function read(bytes _code) public view returns (address) {
                bytes32 hash = keccak256(_code);
                return cache[hash];
            }
        
            function write(bytes _code) public returns (address target) {
                assembly {
                    target := create(0, add(_code, 0x20), mload(_code))
                    switch iszero(extcodesize(target))
                    case 1 {
                        // throw if contract failed to deploy
                        revert(0, 0)
                    }
                }
                bytes32 hash = keccak256(_code);
                cache[hash] = target;
            }
        }

        File 2 of 6: WstETH
        // SPDX-License-Identifier: MIT AND GPL-3.0
        // File: @openzeppelin/contracts/utils/Context.sol
        
        
        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/token/ERC20/IERC20.sol
        
        
        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
        
        
        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/token/ERC20/ERC20.sol
        
        
        pragma solidity >=0.6.0 <0.8.0;
        
        
        
        
        /**
         * @dev Implementation of the {IERC20} interface.
         *
         * This implementation is agnostic to the way tokens are created. This means
         * that a supply mechanism has to be added in a derived contract using {_mint}.
         * For a generic mechanism see {ERC20PresetMinterPauser}.
         *
         * TIP: For a detailed writeup see our guide
         * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
         * to implement supply mechanisms].
         *
         * We have followed general OpenZeppelin guidelines: functions revert instead
         * of returning `false` on failure. This behavior is nonetheless conventional
         * and does not conflict with the expectations of ERC20 applications.
         *
         * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
         * This allows applications to reconstruct the allowance for all accounts just
         * by listening to said events. Other implementations of the EIP may not emit
         * these events, as it isn't required by the specification.
         *
         * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
         * functions have been added to mitigate the well-known issues around setting
         * allowances. See {IERC20-approve}.
         */
        contract ERC20 is Context, IERC20 {
            using SafeMath for uint256;
        
            mapping (address => uint256) private _balances;
        
            mapping (address => mapping (address => uint256)) private _allowances;
        
            uint256 private _totalSupply;
        
            string private _name;
            string private _symbol;
            uint8 private _decimals;
        
            /**
             * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
             * a default value of 18.
             *
             * To select a different value for {decimals}, use {_setupDecimals}.
             *
             * All three of these values are immutable: they can only be set once during
             * construction.
             */
            constructor (string memory name_, string memory symbol_) public {
                _name = name_;
                _symbol = symbol_;
                _decimals = 18;
            }
        
            /**
             * @dev Returns the name of the token.
             */
            function name() public view virtual returns (string memory) {
                return _name;
            }
        
            /**
             * @dev Returns the symbol of the token, usually a shorter version of the
             * name.
             */
            function symbol() public view virtual returns (string memory) {
                return _symbol;
            }
        
            /**
             * @dev Returns the number of decimals used to get its user representation.
             * For example, if `decimals` equals `2`, a balance of `505` tokens should
             * be displayed to a user as `5,05` (`505 / 10 ** 2`).
             *
             * Tokens usually opt for a value of 18, imitating the relationship between
             * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
             * called.
             *
             * NOTE: This information is only used for _display_ purposes: it in
             * no way affects any of the arithmetic of the contract, including
             * {IERC20-balanceOf} and {IERC20-transfer}.
             */
            function decimals() public view virtual returns (uint8) {
                return _decimals;
            }
        
            /**
             * @dev See {IERC20-totalSupply}.
             */
            function totalSupply() public view virtual override returns (uint256) {
                return _totalSupply;
            }
        
            /**
             * @dev See {IERC20-balanceOf}.
             */
            function balanceOf(address account) public view virtual override returns (uint256) {
                return _balances[account];
            }
        
            /**
             * @dev See {IERC20-transfer}.
             *
             * Requirements:
             *
             * - `recipient` cannot be the zero address.
             * - the caller must have a balance of at least `amount`.
             */
            function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(_msgSender(), recipient, amount);
                return true;
            }
        
            /**
             * @dev See {IERC20-allowance}.
             */
            function allowance(address owner, address spender) public view virtual override returns (uint256) {
                return _allowances[owner][spender];
            }
        
            /**
             * @dev See {IERC20-approve}.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function approve(address spender, uint256 amount) public virtual override returns (bool) {
                _approve(_msgSender(), spender, amount);
                return true;
            }
        
            /**
             * @dev See {IERC20-transferFrom}.
             *
             * Emits an {Approval} event indicating the updated allowance. This is not
             * required by the EIP. See the note at the beginning of {ERC20}.
             *
             * Requirements:
             *
             * - `sender` and `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             * - the caller must have allowance for ``sender``'s tokens of at least
             * `amount`.
             */
            function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(sender, recipient, amount);
                _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                return true;
            }
        
            /**
             * @dev Atomically increases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                return true;
            }
        
            /**
             * @dev Atomically decreases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             * - `spender` must have allowance for the caller of at least
             * `subtractedValue`.
             */
            function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                return true;
            }
        
            /**
             * @dev Moves tokens `amount` from `sender` to `recipient`.
             *
             * This is internal function is equivalent to {transfer}, and can be used to
             * e.g. implement automatic token fees, slashing mechanisms, etc.
             *
             * Emits a {Transfer} event.
             *
             * Requirements:
             *
             * - `sender` cannot be the zero address.
             * - `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             */
            function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                require(sender != address(0), "ERC20: transfer from the zero address");
                require(recipient != address(0), "ERC20: transfer to the zero address");
        
                _beforeTokenTransfer(sender, recipient, amount);
        
                _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                _balances[recipient] = _balances[recipient].add(amount);
                emit Transfer(sender, recipient, amount);
            }
        
            /** @dev Creates `amount` tokens and assigns them to `account`, increasing
             * the total supply.
             *
             * Emits a {Transfer} event with `from` set to the zero address.
             *
             * Requirements:
             *
             * - `to` cannot be the zero address.
             */
            function _mint(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: mint to the zero address");
        
                _beforeTokenTransfer(address(0), account, amount);
        
                _totalSupply = _totalSupply.add(amount);
                _balances[account] = _balances[account].add(amount);
                emit Transfer(address(0), account, amount);
            }
        
            /**
             * @dev Destroys `amount` tokens from `account`, reducing the
             * total supply.
             *
             * Emits a {Transfer} event with `to` set to the zero address.
             *
             * Requirements:
             *
             * - `account` cannot be the zero address.
             * - `account` must have at least `amount` tokens.
             */
            function _burn(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: burn from the zero address");
        
                _beforeTokenTransfer(account, address(0), amount);
        
                _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                _totalSupply = _totalSupply.sub(amount);
                emit Transfer(account, address(0), amount);
            }
        
            /**
             * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
             *
             * This internal function is equivalent to `approve`, and can be used to
             * e.g. set automatic allowances for certain subsystems, etc.
             *
             * Emits an {Approval} event.
             *
             * Requirements:
             *
             * - `owner` cannot be the zero address.
             * - `spender` cannot be the zero address.
             */
            function _approve(address owner, address spender, uint256 amount) internal virtual {
                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);
            }
        
            /**
             * @dev Sets {decimals} to a value other than the default one of 18.
             *
             * WARNING: This function should only be called from the constructor. Most
             * applications that interact with token contracts will not expect
             * {decimals} to ever change, and may work incorrectly if it does.
             */
            function _setupDecimals(uint8 decimals_) internal virtual {
                _decimals = decimals_;
            }
        
            /**
             * @dev Hook that is called before any transfer of tokens. This includes
             * minting and burning.
             *
             * Calling conditions:
             *
             * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
             * will be to transferred to `to`.
             * - when `from` is zero, `amount` tokens will be minted for `to`.
             * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
        }
        
        // File: @openzeppelin/contracts/drafts/IERC20Permit.sol
        
        
        pragma solidity >=0.6.0 <0.8.0;
        
        /**
         * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
         * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
         *
         * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
         * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
         * need to send a transaction, and thus is not required to hold Ether at all.
         */
        interface IERC20Permit {
            /**
             * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,
             * given `owner`'s signed approval.
             *
             * IMPORTANT: The same issues {IERC20-approve} has related to transaction
             * ordering also apply here.
             *
             * Emits an {Approval} event.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             * - `deadline` must be a timestamp in the future.
             * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
             * over the EIP712-formatted function arguments.
             * - the signature must use ``owner``'s current nonce (see {nonces}).
             *
             * For more information on the signature format, see the
             * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
             * section].
             */
            function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
        
            /**
             * @dev Returns the current nonce for `owner`. This value must be
             * included whenever a signature is generated for {permit}.
             *
             * Every successful call to {permit} increases ``owner``'s nonce by one. This
             * prevents a signature from being used multiple times.
             */
            function nonces(address owner) external view returns (uint256);
        
            /**
             * @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}.
             */
            // solhint-disable-next-line func-name-mixedcase
            function DOMAIN_SEPARATOR() external view returns (bytes32);
        }
        
        // File: @openzeppelin/contracts/cryptography/ECDSA.sol
        
        
        pragma solidity >=0.6.0 <0.8.0;
        
        /**
         * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
         *
         * These functions can be used to verify that a message was signed by the holder
         * of the private keys of a given address.
         */
        library ECDSA {
            /**
             * @dev Returns the address that signed a hashed message (`hash`) with
             * `signature`. This address can then be used for verification purposes.
             *
             * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
             * this function rejects them by requiring the `s` value to be in the lower
             * half order, and the `v` value to be either 27 or 28.
             *
             * IMPORTANT: `hash` _must_ be the result of a hash operation for the
             * verification to be secure: it is possible to craft signatures that
             * recover to arbitrary addresses for non-hashed data. A safe way to ensure
             * this is by receiving a hash of the original message (which may otherwise
             * be too long), and then calling {toEthSignedMessageHash} on it.
             */
            function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
                // Check the signature length
                if (signature.length != 65) {
                    revert("ECDSA: invalid signature length");
                }
        
                // Divide the signature in r, s and v variables
                bytes32 r;
                bytes32 s;
                uint8 v;
        
                // ecrecover takes the signature parameters, and the only way to get them
                // currently is to use assembly.
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    r := mload(add(signature, 0x20))
                    s := mload(add(signature, 0x40))
                    v := byte(0, mload(add(signature, 0x60)))
                }
        
                return recover(hash, v, r, s);
            }
        
            /**
             * @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`,
             * `r` and `s` signature fields separately.
             */
            function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
                // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                //
                // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                // these malleable signatures as well.
                require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value");
                require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");
        
                // If the signature is valid (and not malleable), return the signer address
                address signer = ecrecover(hash, v, r, s);
                require(signer != address(0), "ECDSA: invalid signature");
        
                return signer;
            }
        
            /**
             * @dev Returns an Ethereum Signed Message, created from a `hash`. This
             * replicates the behavior of the
             * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
             * JSON-RPC method.
             *
             * See {recover}.
             */
            function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
                // 32 is the length in bytes of hash,
                // enforced by the type signature above
                return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
            }
        }
        
        // File: @openzeppelin/contracts/utils/Counters.sol
        
        
        pragma solidity >=0.6.0 <0.8.0;
        
        
        /**
         * @title Counters
         * @author Matt Condon (@shrugs)
         * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
         * of elements in a mapping, issuing ERC721 ids, or counting request ids.
         *
         * Include with `using Counters for Counters.Counter;`
         * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
         * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
         * directly accessed.
         */
        library Counters {
            using SafeMath for uint256;
        
            struct Counter {
                // This variable should never be directly accessed by users of the library: interactions must be restricted to
                // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
                // this feature: see https://github.com/ethereum/solidity/issues/4637
                uint256 _value; // default: 0
            }
        
            function current(Counter storage counter) internal view returns (uint256) {
                return counter._value;
            }
        
            function increment(Counter storage counter) internal {
                // The {SafeMath} overflow check can be skipped here, see the comment at the top
                counter._value += 1;
            }
        
            function decrement(Counter storage counter) internal {
                counter._value = counter._value.sub(1);
            }
        }
        
        // File: @openzeppelin/contracts/drafts/EIP712.sol
        
        
        pragma solidity >=0.6.0 <0.8.0;
        
        /**
         * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
         *
         * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
         * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
         * they need in their contracts using a combination of `abi.encode` and `keccak256`.
         *
         * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
         * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
         * ({_hashTypedDataV4}).
         *
         * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
         * the chain id to protect against replay attacks on an eventual fork of the chain.
         *
         * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
         * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
         *
         * _Available since v3.4._
         */
        abstract contract EIP712 {
            /* solhint-disable var-name-mixedcase */
            // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
            // invalidate the cached domain separator if the chain id changes.
            bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
            uint256 private immutable _CACHED_CHAIN_ID;
        
            bytes32 private immutable _HASHED_NAME;
            bytes32 private immutable _HASHED_VERSION;
            bytes32 private immutable _TYPE_HASH;
            /* solhint-enable var-name-mixedcase */
        
            /**
             * @dev Initializes the domain separator and parameter caches.
             *
             * The meaning of `name` and `version` is specified in
             * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
             *
             * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
             * - `version`: the current major version of the signing domain.
             *
             * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
             * contract upgrade].
             */
            constructor(string memory name, string memory version) internal {
                bytes32 hashedName = keccak256(bytes(name));
                bytes32 hashedVersion = keccak256(bytes(version));
                bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
                _HASHED_NAME = hashedName;
                _HASHED_VERSION = hashedVersion;
                _CACHED_CHAIN_ID = _getChainId();
                _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
                _TYPE_HASH = typeHash;
            }
        
            /**
             * @dev Returns the domain separator for the current chain.
             */
            function _domainSeparatorV4() internal view virtual returns (bytes32) {
                if (_getChainId() == _CACHED_CHAIN_ID) {
                    return _CACHED_DOMAIN_SEPARATOR;
                } else {
                    return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
                }
            }
        
            function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version) private view returns (bytes32) {
                return keccak256(
                    abi.encode(
                        typeHash,
                        name,
                        version,
                        _getChainId(),
                        address(this)
                    )
                );
            }
        
            /**
             * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
             * function returns the hash of the fully encoded EIP712 message for this domain.
             *
             * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
             *
             * ```solidity
             * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
             *     keccak256("Mail(address to,string contents)"),
             *     mailTo,
             *     keccak256(bytes(mailContents))
             * )));
             * address signer = ECDSA.recover(digest, signature);
             * ```
             */
            function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
                return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
            }
        
            function _getChainId() private view returns (uint256 chainId) {
                this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    chainId := chainid()
                }
            }
        }
        
        // File: @openzeppelin/contracts/drafts/ERC20Permit.sol
        
        
        pragma solidity >=0.6.5 <0.8.0;
        
        
        
        
        
        
        /**
         * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
         * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
         *
         * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
         * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
         * need to send a transaction, and thus is not required to hold Ether at all.
         *
         * _Available since v3.4._
         */
        abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
            using Counters for Counters.Counter;
        
            mapping (address => Counters.Counter) private _nonces;
        
            // solhint-disable-next-line var-name-mixedcase
            bytes32 private immutable _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        
            /**
             * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
             *
             * It's a good idea to use the same `name` that is defined as the ERC20 token name.
             */
            constructor(string memory name) internal EIP712(name, "1") {
            }
        
            /**
             * @dev See {IERC20Permit-permit}.
             */
            function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual override {
                // solhint-disable-next-line not-rely-on-time
                require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
        
                bytes32 structHash = keccak256(
                    abi.encode(
                        _PERMIT_TYPEHASH,
                        owner,
                        spender,
                        value,
                        _nonces[owner].current(),
                        deadline
                    )
                );
        
                bytes32 hash = _hashTypedDataV4(structHash);
        
                address signer = ECDSA.recover(hash, v, r, s);
                require(signer == owner, "ERC20Permit: invalid signature");
        
                _nonces[owner].increment();
                _approve(owner, spender, value);
            }
        
            /**
             * @dev See {IERC20Permit-nonces}.
             */
            function nonces(address owner) public view override returns (uint256) {
                return _nonces[owner].current();
            }
        
            /**
             * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
             */
            // solhint-disable-next-line func-name-mixedcase
            function DOMAIN_SEPARATOR() external view override returns (bytes32) {
                return _domainSeparatorV4();
            }
        }
        
        // File: contracts/0.6.12/interfaces/IStETH.sol
        
        // SPDX-FileCopyrightText: 2021 Lido <[email protected]>
        
        
        pragma solidity 0.6.12; // latest available for using OZ
        
        
        
        interface IStETH is IERC20 {
            function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);
        
            function getSharesByPooledEth(uint256 _pooledEthAmount) external view returns (uint256);
        
            function submit(address _referral) external payable returns (uint256);
        }
        
        // File: contracts/0.6.12/WstETH.sol
        
        // SPDX-FileCopyrightText: 2021 Lido <[email protected]>
        
        
        /* See contracts/COMPILERS.md */
        pragma solidity 0.6.12;
        
        
        
        /**
         * @title StETH token wrapper with static balances.
         * @dev It's an ERC20 token that represents the account's share of the total
         * supply of stETH tokens. WstETH token's balance only changes on transfers,
         * unlike StETH that is also changed when oracles report staking rewards and
         * penalties. It's a "power user" token for DeFi protocols which don't
         * support rebasable tokens.
         *
         * The contract is also a trustless wrapper that accepts stETH tokens and mints
         * wstETH in return. Then the user unwraps, the contract burns user's wstETH
         * and sends user locked stETH in return.
         *
         * The contract provides the staking shortcut: user can send ETH with regular
         * transfer and get wstETH in return. The contract will send ETH to Lido submit
         * method, staking it and wrapping the received stETH.
         *
         */
        contract WstETH is ERC20Permit {
            IStETH public stETH;
        
            /**
             * @param _stETH address of the StETH token to wrap
             */
            constructor(IStETH _stETH)
                public
                ERC20Permit("Wrapped liquid staked Ether 2.0")
                ERC20("Wrapped liquid staked Ether 2.0", "wstETH")
            {
                stETH = _stETH;
            }
        
            /**
             * @notice Exchanges stETH to wstETH
             * @param _stETHAmount amount of stETH to wrap in exchange for wstETH
             * @dev Requirements:
             *  - `_stETHAmount` must be non-zero
             *  - msg.sender must approve at least `_stETHAmount` stETH to this
             *    contract.
             *  - msg.sender must have at least `_stETHAmount` of stETH.
             * User should first approve _stETHAmount to the WstETH contract
             * @return Amount of wstETH user receives after wrap
             */
            function wrap(uint256 _stETHAmount) external returns (uint256) {
                require(_stETHAmount > 0, "wstETH: can't wrap zero stETH");
                uint256 wstETHAmount = stETH.getSharesByPooledEth(_stETHAmount);
                _mint(msg.sender, wstETHAmount);
                stETH.transferFrom(msg.sender, address(this), _stETHAmount);
                return wstETHAmount;
            }
        
            /**
             * @notice Exchanges wstETH to stETH
             * @param _wstETHAmount amount of wstETH to uwrap in exchange for stETH
             * @dev Requirements:
             *  - `_wstETHAmount` must be non-zero
             *  - msg.sender must have at least `_wstETHAmount` wstETH.
             * @return Amount of stETH user receives after unwrap
             */
            function unwrap(uint256 _wstETHAmount) external returns (uint256) {
                require(_wstETHAmount > 0, "wstETH: zero amount unwrap not allowed");
                uint256 stETHAmount = stETH.getPooledEthByShares(_wstETHAmount);
                _burn(msg.sender, _wstETHAmount);
                stETH.transfer(msg.sender, stETHAmount);
                return stETHAmount;
            }
        
            /**
            * @notice Shortcut to stake ETH and auto-wrap returned stETH
            */
            receive() external payable {
                uint256 shares = stETH.submit{value: msg.value}(address(0));
                _mint(msg.sender, shares);
            }
        
            /**
             * @notice Get amount of wstETH for a given amount of stETH
             * @param _stETHAmount amount of stETH
             * @return Amount of wstETH for a given stETH amount
             */
            function getWstETHByStETH(uint256 _stETHAmount) external view returns (uint256) {
                return stETH.getSharesByPooledEth(_stETHAmount);
            }
        
            /**
             * @notice Get amount of stETH for a given amount of wstETH
             * @param _wstETHAmount amount of wstETH
             * @return Amount of stETH for a given wstETH amount
             */
            function getStETHByWstETH(uint256 _wstETHAmount) external view returns (uint256) {
                return stETH.getPooledEthByShares(_wstETHAmount);
            }
        
            /**
             * @notice Get amount of stETH for a one wstETH
             * @return Amount of stETH for 1 wstETH
             */
            function stEthPerToken() external view returns (uint256) {
                return stETH.getPooledEthByShares(1 ether);
            }
        
            /**
             * @notice Get amount of wstETH for a one stETH
             * @return Amount of wstETH for a 1 stETH
             */
            function tokensPerStEth() external view returns (uint256) {
                return stETH.getSharesByPooledEth(1 ether);
            }
        }

        File 3 of 6: Vat
        // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/vat.sol
        pragma solidity =0.5.12;
        
        ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/vat.sol
        /// vat.sol -- Dai CDP database
        
        // Copyright (C) 2018 Rain <[email protected]>
        //
        // 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; */
        
        contract Vat {
            // --- Auth ---
            mapping (address => uint) public wards;
            function rely(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; }
            function deny(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 0; }
            modifier auth {
                require(wards[msg.sender] == 1, "Vat/not-authorized");
                _;
            }
        
            mapping(address => mapping (address => uint)) public can;
            function hope(address usr) external note { can[msg.sender][usr] = 1; }
            function nope(address usr) external note { can[msg.sender][usr] = 0; }
            function wish(address bit, address usr) internal view returns (bool) {
                return either(bit == usr, can[bit][usr] == 1);
            }
        
            // --- Data ---
            struct Ilk {
                uint256 Art;   // Total Normalised Debt     [wad]
                uint256 rate;  // Accumulated Rates         [ray]
                uint256 spot;  // Price with Safety Margin  [ray]
                uint256 line;  // Debt Ceiling              [rad]
                uint256 dust;  // Urn Debt Floor            [rad]
            }
            struct Urn {
                uint256 ink;   // Locked Collateral  [wad]
                uint256 art;   // Normalised Debt    [wad]
            }
        
            mapping (bytes32 => Ilk)                       public ilks;
            mapping (bytes32 => mapping (address => Urn )) public urns;
            mapping (bytes32 => mapping (address => uint)) public gem;  // [wad]
            mapping (address => uint256)                   public dai;  // [rad]
            mapping (address => uint256)                   public sin;  // [rad]
        
            uint256 public debt;  // Total Dai Issued    [rad]
            uint256 public vice;  // Total Unbacked Dai  [rad]
            uint256 public Line;  // Total Debt Ceiling  [rad]
            uint256 public live;  // Access Flag
        
            // --- Logs ---
            event LogNote(
                bytes4   indexed  sig,
                bytes32  indexed  arg1,
                bytes32  indexed  arg2,
                bytes32  indexed  arg3,
                bytes             data
            ) anonymous;
        
            modifier note {
                _;
                assembly {
                    // log an 'anonymous' event with a constant 6 words of calldata
                    // and four indexed topics: the selector and the first three args
                    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
                         calldataload(4),                     // arg1
                         calldataload(36),                    // arg2
                         calldataload(68)                     // arg3
                        )
                }
            }
        
            // --- Init ---
            constructor() public {
                wards[msg.sender] = 1;
                live = 1;
            }
        
            // --- Math ---
            function add(uint x, int y) internal pure returns (uint z) {
                z = x + uint(y);
                require(y >= 0 || z <= x);
                require(y <= 0 || z >= x);
            }
            function sub(uint x, int y) internal pure returns (uint z) {
                z = x - uint(y);
                require(y <= 0 || z <= x);
                require(y >= 0 || z >= x);
            }
            function mul(uint x, int y) internal pure returns (int z) {
                z = int(x) * y;
                require(int(x) >= 0);
                require(y == 0 || z / y == int(x));
            }
            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);
            }
            function mul(uint x, uint y) internal pure returns (uint z) {
                require(y == 0 || (z = x * y) / y == x);
            }
        
            // --- Administration ---
            function init(bytes32 ilk) external note auth {
                require(ilks[ilk].rate == 0, "Vat/ilk-already-init");
                ilks[ilk].rate = 10 ** 27;
            }
            function file(bytes32 what, uint data) external note auth {
                require(live == 1, "Vat/not-live");
                if (what == "Line") Line = data;
                else revert("Vat/file-unrecognized-param");
            }
            function file(bytes32 ilk, bytes32 what, uint data) external note auth {
                require(live == 1, "Vat/not-live");
                if (what == "spot") ilks[ilk].spot = data;
                else if (what == "line") ilks[ilk].line = data;
                else if (what == "dust") ilks[ilk].dust = data;
                else revert("Vat/file-unrecognized-param");
            }
            function cage() external note auth {
                live = 0;
            }
        
            // --- Fungibility ---
            function slip(bytes32 ilk, address usr, int256 wad) external note auth {
                gem[ilk][usr] = add(gem[ilk][usr], wad);
            }
            function flux(bytes32 ilk, address src, address dst, uint256 wad) external note {
                require(wish(src, msg.sender), "Vat/not-allowed");
                gem[ilk][src] = sub(gem[ilk][src], wad);
                gem[ilk][dst] = add(gem[ilk][dst], wad);
            }
            function move(address src, address dst, uint256 rad) external note {
                require(wish(src, msg.sender), "Vat/not-allowed");
                dai[src] = sub(dai[src], rad);
                dai[dst] = add(dai[dst], rad);
            }
        
            function either(bool x, bool y) internal pure returns (bool z) {
                assembly{ z := or(x, y)}
            }
            function both(bool x, bool y) internal pure returns (bool z) {
                assembly{ z := and(x, y)}
            }
        
            // --- CDP Manipulation ---
            function frob(bytes32 i, address u, address v, address w, int dink, int dart) external note {
                // system is live
                require(live == 1, "Vat/not-live");
        
                Urn memory urn = urns[i][u];
                Ilk memory ilk = ilks[i];
                // ilk has been initialised
                require(ilk.rate != 0, "Vat/ilk-not-init");
        
                urn.ink = add(urn.ink, dink);
                urn.art = add(urn.art, dart);
                ilk.Art = add(ilk.Art, dart);
        
                int dtab = mul(ilk.rate, dart);
                uint tab = mul(ilk.rate, urn.art);
                debt     = add(debt, dtab);
        
                // either debt has decreased, or debt ceilings are not exceeded
                require(either(dart <= 0, both(mul(ilk.Art, ilk.rate) <= ilk.line, debt <= Line)), "Vat/ceiling-exceeded");
                // urn is either less risky than before, or it is safe
                require(either(both(dart <= 0, dink >= 0), tab <= mul(urn.ink, ilk.spot)), "Vat/not-safe");
        
                // urn is either more safe, or the owner consents
                require(either(both(dart <= 0, dink >= 0), wish(u, msg.sender)), "Vat/not-allowed-u");
                // collateral src consents
                require(either(dink <= 0, wish(v, msg.sender)), "Vat/not-allowed-v");
                // debt dst consents
                require(either(dart >= 0, wish(w, msg.sender)), "Vat/not-allowed-w");
        
                // urn has no debt, or a non-dusty amount
                require(either(urn.art == 0, tab >= ilk.dust), "Vat/dust");
        
                gem[i][v] = sub(gem[i][v], dink);
                dai[w]    = add(dai[w],    dtab);
        
                urns[i][u] = urn;
                ilks[i]    = ilk;
            }
            // --- CDP Fungibility ---
            function fork(bytes32 ilk, address src, address dst, int dink, int dart) external note {
                Urn storage u = urns[ilk][src];
                Urn storage v = urns[ilk][dst];
                Ilk storage i = ilks[ilk];
        
                u.ink = sub(u.ink, dink);
                u.art = sub(u.art, dart);
                v.ink = add(v.ink, dink);
                v.art = add(v.art, dart);
        
                uint utab = mul(u.art, i.rate);
                uint vtab = mul(v.art, i.rate);
        
                // both sides consent
                require(both(wish(src, msg.sender), wish(dst, msg.sender)), "Vat/not-allowed");
        
                // both sides safe
                require(utab <= mul(u.ink, i.spot), "Vat/not-safe-src");
                require(vtab <= mul(v.ink, i.spot), "Vat/not-safe-dst");
        
                // both sides non-dusty
                require(either(utab >= i.dust, u.art == 0), "Vat/dust-src");
                require(either(vtab >= i.dust, v.art == 0), "Vat/dust-dst");
            }
            // --- CDP Confiscation ---
            function grab(bytes32 i, address u, address v, address w, int dink, int dart) external note auth {
                Urn storage urn = urns[i][u];
                Ilk storage ilk = ilks[i];
        
                urn.ink = add(urn.ink, dink);
                urn.art = add(urn.art, dart);
                ilk.Art = add(ilk.Art, dart);
        
                int dtab = mul(ilk.rate, dart);
        
                gem[i][v] = sub(gem[i][v], dink);
                sin[w]    = sub(sin[w],    dtab);
                vice      = sub(vice,      dtab);
            }
        
            // --- Settlement ---
            function heal(uint rad) external note {
                address u = msg.sender;
                sin[u] = sub(sin[u], rad);
                dai[u] = sub(dai[u], rad);
                vice   = sub(vice,   rad);
                debt   = sub(debt,   rad);
            }
            function suck(address u, address v, uint rad) external note auth {
                sin[u] = add(sin[u], rad);
                dai[v] = add(dai[v], rad);
                vice   = add(vice,   rad);
                debt   = add(debt,   rad);
            }
        
            // --- Rates ---
            function fold(bytes32 i, address u, int rate) external note auth {
                require(live == 1, "Vat/not-live");
                Ilk storage ilk = ilks[i];
                ilk.rate = add(ilk.rate, rate);
                int rad  = mul(ilk.Art, rate);
                dai[u]   = add(dai[u], rad);
                debt     = add(debt,   rad);
            }
        }

        File 4 of 6: GemJoin
        // hevm: flattened sources of src/join.sol
        
        pragma solidity >=0.5.12;
        
        ////// 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
                        )
                }
            }
        }
        
        ////// src/join.sol
        
        /// join.sol -- Basic token adapters
        
        // Copyright (C) 2018 Rain <[email protected]>
        //
        // 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"; */
        
        interface GemLike_3 {
            function decimals() external view returns (uint);
            function transfer(address,uint) external returns (bool);
            function transferFrom(address,address,uint) external returns (bool);
        }
        
        interface DSTokenLike {
            function mint(address,uint) external;
            function burn(address,uint) external;
        }
        
        interface VatLike_6 {
            function slip(bytes32,address,int) external;
            function move(address,address,uint) external;
        }
        
        /*
            Here we provide *adapters* to connect the Vat to arbitrary external
            token implementations, creating a bounded context for the Vat. The
            adapters here are provided as working examples:
        
              - `GemJoin`: For well behaved ERC20 tokens, with simple transfer
                           semantics.
        
              - `ETHJoin`: For native Ether.
        
              - `DaiJoin`: For connecting internal Dai balances to an external
                           `DSToken` implementation.
        
            In practice, adapter implementations will be varied and specific to
            individual collateral types, accounting for different transfer
            semantics and token standards.
        
            Adapters need to implement two basic methods:
        
              - `join`: enter collateral into the system
              - `exit`: remove collateral from the system
        
        */
        
        contract GemJoin is LibNote {
            // --- Auth ---
            mapping (address => uint) public wards;
            function rely(address usr) external note auth { wards[usr] = 1; }
            function deny(address usr) external note auth { wards[usr] = 0; }
            modifier auth {
                require(wards[msg.sender] == 1, "GemJoin/not-authorized");
                _;
            }
        
            VatLike_6 public vat;   // CDP Engine
            bytes32 public ilk;   // Collateral Type
            GemLike_3 public gem;
            uint    public dec;
            uint    public live;  // Active Flag
        
            constructor(address vat_, bytes32 ilk_, address gem_) public {
                wards[msg.sender] = 1;
                live = 1;
                vat = VatLike_6(vat_);
                ilk = ilk_;
                gem = GemLike_3(gem_);
                dec = gem.decimals();
            }
            function cage() external note auth {
                live = 0;
            }
            function join(address usr, uint wad) external note {
                require(live == 1, "GemJoin/not-live");
                require(int(wad) >= 0, "GemJoin/overflow");
                vat.slip(ilk, usr, int(wad));
                require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer");
            }
            function exit(address usr, uint wad) external note {
                require(wad <= 2 ** 255, "GemJoin/overflow");
                vat.slip(ilk, msg.sender, -int(wad));
                require(gem.transfer(usr, wad), "GemJoin/failed-transfer");
            }
        }
        
        contract DaiJoin is LibNote {
            // --- Auth ---
            mapping (address => uint) public wards;
            function rely(address usr) external note auth { wards[usr] = 1; }
            function deny(address usr) external note auth { wards[usr] = 0; }
            modifier auth {
                require(wards[msg.sender] == 1, "DaiJoin/not-authorized");
                _;
            }
        
            VatLike_6 public vat;      // CDP Engine
            DSTokenLike public dai;  // Stablecoin Token
            uint    public live;     // Active Flag
        
            constructor(address vat_, address dai_) public {
                wards[msg.sender] = 1;
                live = 1;
                vat = VatLike_6(vat_);
                dai = DSTokenLike(dai_);
            }
            function cage() external note auth {
                live = 0;
            }
            uint constant ONE = 10 ** 27;
            function mul(uint x, uint y) internal pure returns (uint z) {
                require(y == 0 || (z = x * y) / y == x);
            }
            function join(address usr, uint wad) external note {
                vat.move(address(this), usr, mul(ONE, wad));
                dai.burn(msg.sender, wad);
            }
            function exit(address usr, uint wad) external note {
                require(live == 1, "DaiJoin/not-live");
                vat.move(msg.sender, address(this), mul(ONE, wad));
                dai.mint(usr, wad);
            }
        }

        File 5 of 6: DssProxyActions
        // hevm: flattened sources of /nix/store/sxr9nv6bdacjzw8vhns72bxjga458x34-dss-proxy-actions-53f1d75/src/DssProxyActions.sol
        pragma solidity =0.5.12;
        
        ////// /nix/store/sxr9nv6bdacjzw8vhns72bxjga458x34-dss-proxy-actions-53f1d75/src/DssProxyActions.sol
        /* pragma solidity 0.5.12; */
        
        contract GemLike {
            function approve(address, uint) public;
            function transfer(address, uint) public;
            function transferFrom(address, address, uint) public;
            function deposit() public payable;
            function withdraw(uint) public;
        }
        
        contract ManagerLike {
            function cdpCan(address, uint, address) public view returns (uint);
            function ilks(uint) public view returns (bytes32);
            function owns(uint) public view returns (address);
            function urns(uint) public view returns (address);
            function vat() public view returns (address);
            function open(bytes32, address) public returns (uint);
            function give(uint, address) public;
            function cdpAllow(uint, address, uint) public;
            function urnAllow(address, uint) public;
            function frob(uint, int, int) public;
            function flux(uint, address, uint) public;
            function move(uint, address, uint) public;
            function exit(address, uint, address, uint) public;
            function quit(uint, address) public;
            function enter(address, uint) public;
            function shift(uint, uint) public;
        }
        
        contract VatLike {
            function can(address, address) public view returns (uint);
            function ilks(bytes32) public view returns (uint, uint, uint, uint, uint);
            function dai(address) public view returns (uint);
            function urns(bytes32, address) public view returns (uint, uint);
            function frob(bytes32, address, address, address, int, int) public;
            function hope(address) public;
            function move(address, address, uint) public;
        }
        
        contract GemJoinLike {
            function dec() public returns (uint);
            function gem() public returns (GemLike);
            function join(address, uint) public payable;
            function exit(address, uint) public;
        }
        
        contract GNTJoinLike {
            function bags(address) public view returns (address);
            function make(address) public returns (address);
        }
        
        contract DaiJoinLike {
            function vat() public returns (VatLike);
            function dai() public returns (GemLike);
            function join(address, uint) public payable;
            function exit(address, uint) public;
        }
        
        contract HopeLike {
            function hope(address) public;
            function nope(address) public;
        }
        
        contract EndLike {
            function fix(bytes32) public view returns (uint);
            function cash(bytes32, uint) public;
            function free(bytes32) public;
            function pack(uint) public;
            function skim(bytes32, address) public;
        }
        
        contract JugLike {
            function drip(bytes32) public returns (uint);
        }
        
        contract PotLike {
            function pie(address) public view returns (uint);
            function drip() public returns (uint);
            function join(uint) public;
            function exit(uint) public;
        }
        
        contract ProxyRegistryLike {
            function proxies(address) public view returns (address);
            function build(address) public returns (address);
        }
        
        contract ProxyLike {
            function owner() public view returns (address);
        }
        
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        // WARNING: These functions meant to be used as a a library for a DSProxy. Some are unsafe if you call them directly.
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        
        contract Common {
            uint256 constant RAY = 10 ** 27;
        
            // Internal functions
        
            function mul(uint x, uint y) internal pure returns (uint z) {
                require(y == 0 || (z = x * y) / y == x, "mul-overflow");
            }
        
            // Public functions
        
            function daiJoin_join(address apt, address urn, uint wad) public {
                // Gets DAI from the user's wallet
                DaiJoinLike(apt).dai().transferFrom(msg.sender, address(this), wad);
                // Approves adapter to take the DAI amount
                DaiJoinLike(apt).dai().approve(apt, wad);
                // Joins DAI into the vat
                DaiJoinLike(apt).join(urn, wad);
            }
        }
        
        contract DssProxyActions is Common {
            // Internal functions
        
            function sub(uint x, uint y) internal pure returns (uint z) {
                require((z = x - y) <= x, "sub-overflow");
            }
        
            function toInt(uint x) internal pure returns (int y) {
                y = int(x);
                require(y >= 0, "int-overflow");
            }
        
            function toRad(uint wad) internal pure returns (uint rad) {
                rad = mul(wad, 10 ** 27);
            }
        
            function convertTo18(address gemJoin, uint256 amt) internal returns (uint256 wad) {
                // For those collaterals that have less than 18 decimals precision we need to do the conversion before passing to frob function
                // Adapters will automatically handle the difference of precision
                wad = mul(
                    amt,
                    10 ** (18 - GemJoinLike(gemJoin).dec())
                );
            }
        
            function _getDrawDart(
                address vat,
                address jug,
                address urn,
                bytes32 ilk,
                uint wad
            ) internal returns (int dart) {
                // Updates stability fee rate
                uint rate = JugLike(jug).drip(ilk);
        
                // Gets DAI balance of the urn in the vat
                uint dai = VatLike(vat).dai(urn);
        
                // If there was already enough DAI in the vat balance, just exits it without adding more debt
                if (dai < mul(wad, RAY)) {
                    // Calculates the needed dart so together with the existing dai in the vat is enough to exit wad amount of DAI tokens
                    dart = toInt(sub(mul(wad, RAY), dai) / rate);
                    // This is neeeded due lack of precision. It might need to sum an extra dart wei (for the given DAI wad amount)
                    dart = mul(uint(dart), rate) < mul(wad, RAY) ? dart + 1 : dart;
                }
            }
        
            function _getWipeDart(
                address vat,
                uint dai,
                address urn,
                bytes32 ilk
            ) internal view returns (int dart) {
                // Gets actual rate from the vat
                (, uint rate,,,) = VatLike(vat).ilks(ilk);
                // Gets actual art value of the urn
                (, uint art) = VatLike(vat).urns(ilk, urn);
        
                // Uses the whole dai balance in the vat to reduce the debt
                dart = toInt(dai / rate);
                // Checks the calculated dart is not higher than urn.art (total debt), otherwise uses its value
                dart = uint(dart) <= art ? - dart : - toInt(art);
            }
        
            function _getWipeAllWad(
                address vat,
                address usr,
                address urn,
                bytes32 ilk
            ) internal view returns (uint wad) {
                // Gets actual rate from the vat
                (, uint rate,,,) = VatLike(vat).ilks(ilk);
                // Gets actual art value of the urn
                (, uint art) = VatLike(vat).urns(ilk, urn);
                // Gets actual dai amount in the urn
                uint dai = VatLike(vat).dai(usr);
        
                uint rad = sub(mul(art, rate), dai);
                wad = rad / RAY;
        
                // If the rad precision has some dust, it will need to request for 1 extra wad wei
                wad = mul(wad, RAY) < rad ? wad + 1 : wad;
            }
        
            // Public functions
        
            function transfer(address gem, address dst, uint wad) public {
                GemLike(gem).transfer(dst, wad);
            }
        
            function ethJoin_join(address apt, address urn) public payable {
                // Wraps ETH in WETH
                GemJoinLike(apt).gem().deposit.value(msg.value)();
                // Approves adapter to take the WETH amount
                GemJoinLike(apt).gem().approve(address(apt), msg.value);
                // Joins WETH collateral into the vat
                GemJoinLike(apt).join(urn, msg.value);
            }
        
            function gemJoin_join(address apt, address urn, uint wad, bool transferFrom) public {
                // Only executes for tokens that have approval/transferFrom implementation
                if (transferFrom) {
                    // Gets token from the user's wallet
                    GemJoinLike(apt).gem().transferFrom(msg.sender, address(this), wad);
                    // Approves adapter to take the token amount
                    GemJoinLike(apt).gem().approve(apt, wad);
                }
                // Joins token collateral into the vat
                GemJoinLike(apt).join(urn, wad);
            }
        
            function hope(
                address obj,
                address usr
            ) public {
                HopeLike(obj).hope(usr);
            }
        
            function nope(
                address obj,
                address usr
            ) public {
                HopeLike(obj).nope(usr);
            }
        
            function open(
                address manager,
                bytes32 ilk,
                address usr
            ) public returns (uint cdp) {
                cdp = ManagerLike(manager).open(ilk, usr);
            }
        
            function give(
                address manager,
                uint cdp,
                address usr
            ) public {
                ManagerLike(manager).give(cdp, usr);
            }
        
            function giveToProxy(
                address proxyRegistry,
                address manager,
                uint cdp,
                address dst
            ) public {
                // Gets actual proxy address
                address proxy = ProxyRegistryLike(proxyRegistry).proxies(dst);
                // Checks if the proxy address already existed and dst address is still the owner
                if (proxy == address(0) || ProxyLike(proxy).owner() != dst) {
                    uint csize;
                    assembly {
                        csize := extcodesize(dst)
                    }
                    // We want to avoid creating a proxy for a contract address that might not be able to handle proxies, then losing the CDP
                    require(csize == 0, "Dst-is-a-contract");
                    // Creates the proxy for the dst address
                    proxy = ProxyRegistryLike(proxyRegistry).build(dst);
                }
                // Transfers CDP to the dst proxy
                give(manager, cdp, proxy);
            }
        
            function cdpAllow(
                address manager,
                uint cdp,
                address usr,
                uint ok
            ) public {
                ManagerLike(manager).cdpAllow(cdp, usr, ok);
            }
        
            function urnAllow(
                address manager,
                address usr,
                uint ok
            ) public {
                ManagerLike(manager).urnAllow(usr, ok);
            }
        
            function flux(
                address manager,
                uint cdp,
                address dst,
                uint wad
            ) public {
                ManagerLike(manager).flux(cdp, dst, wad);
            }
        
            function move(
                address manager,
                uint cdp,
                address dst,
                uint rad
            ) public {
                ManagerLike(manager).move(cdp, dst, rad);
            }
        
            function frob(
                address manager,
                uint cdp,
                int dink,
                int dart
            ) public {
                ManagerLike(manager).frob(cdp, dink, dart);
            }
        
            function quit(
                address manager,
                uint cdp,
                address dst
            ) public {
                ManagerLike(manager).quit(cdp, dst);
            }
        
            function enter(
                address manager,
                address src,
                uint cdp
            ) public {
                ManagerLike(manager).enter(src, cdp);
            }
        
            function shift(
                address manager,
                uint cdpSrc,
                uint cdpOrg
            ) public {
                ManagerLike(manager).shift(cdpSrc, cdpOrg);
            }
        
            function makeGemBag(
                address gemJoin
            ) public returns (address bag) {
                bag = GNTJoinLike(gemJoin).make(address(this));
            }
        
            function lockETH(
                address manager,
                address ethJoin,
                uint cdp
            ) public payable {
                // Receives ETH amount, converts it to WETH and joins it into the vat
                ethJoin_join(ethJoin, address(this));
                // Locks WETH amount into the CDP
                VatLike(ManagerLike(manager).vat()).frob(
                    ManagerLike(manager).ilks(cdp),
                    ManagerLike(manager).urns(cdp),
                    address(this),
                    address(this),
                    toInt(msg.value),
                    0
                );
            }
        
            function safeLockETH(
                address manager,
                address ethJoin,
                uint cdp,
                address owner
            ) public payable {
                require(ManagerLike(manager).owns(cdp) == owner, "owner-missmatch");
                lockETH(manager, ethJoin, cdp);
            }
        
            function lockGem(
                address manager,
                address gemJoin,
                uint cdp,
                uint wad,
                bool transferFrom
            ) public {
                // Takes token amount from user's wallet and joins into the vat
                gemJoin_join(gemJoin, address(this), wad, transferFrom);
                // Locks token amount into the CDP
                VatLike(ManagerLike(manager).vat()).frob(
                    ManagerLike(manager).ilks(cdp),
                    ManagerLike(manager).urns(cdp),
                    address(this),
                    address(this),
                    toInt(convertTo18(gemJoin, wad)),
                    0
                );
            }
        
            function safeLockGem(
                address manager,
                address gemJoin,
                uint cdp,
                uint wad,
                bool transferFrom,
                address owner
            ) public {
                require(ManagerLike(manager).owns(cdp) == owner, "owner-missmatch");
                lockGem(manager, gemJoin, cdp, wad, transferFrom);
            }
        
            function freeETH(
                address manager,
                address ethJoin,
                uint cdp,
                uint wad
            ) public {
                // Unlocks WETH amount from the CDP
                frob(manager, cdp, -toInt(wad), 0);
                // Moves the amount from the CDP urn to proxy's address
                flux(manager, cdp, address(this), wad);
                // Exits WETH amount to proxy address as a token
                GemJoinLike(ethJoin).exit(address(this), wad);
                // Converts WETH to ETH
                GemJoinLike(ethJoin).gem().withdraw(wad);
                // Sends ETH back to the user's wallet
                msg.sender.transfer(wad);
            }
        
            function freeGem(
                address manager,
                address gemJoin,
                uint cdp,
                uint wad
            ) public {
                uint wad18 = convertTo18(gemJoin, wad);
                // Unlocks token amount from the CDP
                frob(manager, cdp, -toInt(wad18), 0);
                // Moves the amount from the CDP urn to proxy's address
                flux(manager, cdp, address(this), wad18);
                // Exits token amount to the user's wallet as a token
                GemJoinLike(gemJoin).exit(msg.sender, wad);
            }
        
            function exitETH(
                address manager,
                address ethJoin,
                uint cdp,
                uint wad
            ) public {
                // Moves the amount from the CDP urn to proxy's address
                flux(manager, cdp, address(this), wad);
        
                // Exits WETH amount to proxy address as a token
                GemJoinLike(ethJoin).exit(address(this), wad);
                // Converts WETH to ETH
                GemJoinLike(ethJoin).gem().withdraw(wad);
                // Sends ETH back to the user's wallet
                msg.sender.transfer(wad);
            }
        
            function exitGem(
                address manager,
                address gemJoin,
                uint cdp,
                uint wad
            ) public {
                // Moves the amount from the CDP urn to proxy's address
                flux(manager, cdp, address(this), convertTo18(gemJoin, wad));
        
                // Exits token amount to the user's wallet as a token
                GemJoinLike(gemJoin).exit(msg.sender, wad);
            }
        
            function draw(
                address manager,
                address jug,
                address daiJoin,
                uint cdp,
                uint wad
            ) public {
                address urn = ManagerLike(manager).urns(cdp);
                address vat = ManagerLike(manager).vat();
                bytes32 ilk = ManagerLike(manager).ilks(cdp);
                // Generates debt in the CDP
                frob(manager, cdp, 0, _getDrawDart(vat, jug, urn, ilk, wad));
                // Moves the DAI amount (balance in the vat in rad) to proxy's address
                move(manager, cdp, address(this), toRad(wad));
                // Allows adapter to access to proxy's DAI balance in the vat
                if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
                    VatLike(vat).hope(daiJoin);
                }
                // Exits DAI to the user's wallet as a token
                DaiJoinLike(daiJoin).exit(msg.sender, wad);
            }
        
            function wipe(
                address manager,
                address daiJoin,
                uint cdp,
                uint wad
            ) public {
                address vat = ManagerLike(manager).vat();
                address urn = ManagerLike(manager).urns(cdp);
                bytes32 ilk = ManagerLike(manager).ilks(cdp);
        
                address own = ManagerLike(manager).owns(cdp);
                if (own == address(this) || ManagerLike(manager).cdpCan(own, cdp, address(this)) == 1) {
                    // Joins DAI amount into the vat
                    daiJoin_join(daiJoin, urn, wad);
                    // Paybacks debt to the CDP
                    frob(manager, cdp, 0, _getWipeDart(vat, VatLike(vat).dai(urn), urn, ilk));
                } else {
                     // Joins DAI amount into the vat
                    daiJoin_join(daiJoin, address(this), wad);
                    // Paybacks debt to the CDP
                    VatLike(vat).frob(
                        ilk,
                        urn,
                        address(this),
                        address(this),
                        0,
                        _getWipeDart(vat, wad * RAY, urn, ilk)
                    );
                }
            }
        
            function safeWipe(
                address manager,
                address daiJoin,
                uint cdp,
                uint wad,
                address owner
            ) public {
                require(ManagerLike(manager).owns(cdp) == owner, "owner-missmatch");
                wipe(manager, daiJoin, cdp, wad);
            }
        
            function wipeAll(
                address manager,
                address daiJoin,
                uint cdp
            ) public {
                address vat = ManagerLike(manager).vat();
                address urn = ManagerLike(manager).urns(cdp);
                bytes32 ilk = ManagerLike(manager).ilks(cdp);
                (, uint art) = VatLike(vat).urns(ilk, urn);
        
                address own = ManagerLike(manager).owns(cdp);
                if (own == address(this) || ManagerLike(manager).cdpCan(own, cdp, address(this)) == 1) {
                    // Joins DAI amount into the vat
                    daiJoin_join(daiJoin, urn, _getWipeAllWad(vat, urn, urn, ilk));
                    // Paybacks debt to the CDP
                    frob(manager, cdp, 0, -int(art));
                } else {
                    // Joins DAI amount into the vat
                    daiJoin_join(daiJoin, address(this), _getWipeAllWad(vat, address(this), urn, ilk));
                    // Paybacks debt to the CDP
                    VatLike(vat).frob(
                        ilk,
                        urn,
                        address(this),
                        address(this),
                        0,
                        -int(art)
                    );
                }
            }
        
            function safeWipeAll(
                address manager,
                address daiJoin,
                uint cdp,
                address owner
            ) public {
                require(ManagerLike(manager).owns(cdp) == owner, "owner-missmatch");
                wipeAll(manager, daiJoin, cdp);
            }
        
            function lockETHAndDraw(
                address manager,
                address jug,
                address ethJoin,
                address daiJoin,
                uint cdp,
                uint wadD
            ) public payable {
                address urn = ManagerLike(manager).urns(cdp);
                address vat = ManagerLike(manager).vat();
                bytes32 ilk = ManagerLike(manager).ilks(cdp);
                // Receives ETH amount, converts it to WETH and joins it into the vat
                ethJoin_join(ethJoin, urn);
                // Locks WETH amount into the CDP and generates debt
                frob(manager, cdp, toInt(msg.value), _getDrawDart(vat, jug, urn, ilk, wadD));
                // Moves the DAI amount (balance in the vat in rad) to proxy's address
                move(manager, cdp, address(this), toRad(wadD));
                // Allows adapter to access to proxy's DAI balance in the vat
                if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
                    VatLike(vat).hope(daiJoin);
                }
                // Exits DAI to the user's wallet as a token
                DaiJoinLike(daiJoin).exit(msg.sender, wadD);
            }
        
            function openLockETHAndDraw(
                address manager,
                address jug,
                address ethJoin,
                address daiJoin,
                bytes32 ilk,
                uint wadD
            ) public payable returns (uint cdp) {
                cdp = open(manager, ilk, address(this));
                lockETHAndDraw(manager, jug, ethJoin, daiJoin, cdp, wadD);
            }
        
            function lockGemAndDraw(
                address manager,
                address jug,
                address gemJoin,
                address daiJoin,
                uint cdp,
                uint wadC,
                uint wadD,
                bool transferFrom
            ) public {
                address urn = ManagerLike(manager).urns(cdp);
                address vat = ManagerLike(manager).vat();
                bytes32 ilk = ManagerLike(manager).ilks(cdp);
                // Takes token amount from user's wallet and joins into the vat
                gemJoin_join(gemJoin, urn, wadC, transferFrom);
                // Locks token amount into the CDP and generates debt
                frob(manager, cdp, toInt(convertTo18(gemJoin, wadC)), _getDrawDart(vat, jug, urn, ilk, wadD));
                // Moves the DAI amount (balance in the vat in rad) to proxy's address
                move(manager, cdp, address(this), toRad(wadD));
                // Allows adapter to access to proxy's DAI balance in the vat
                if (VatLike(vat).can(address(this), address(daiJoin)) == 0) {
                    VatLike(vat).hope(daiJoin);
                }
                // Exits DAI to the user's wallet as a token
                DaiJoinLike(daiJoin).exit(msg.sender, wadD);
            }
        
            function openLockGemAndDraw(
                address manager,
                address jug,
                address gemJoin,
                address daiJoin,
                bytes32 ilk,
                uint wadC,
                uint wadD,
                bool transferFrom
            ) public returns (uint cdp) {
                cdp = open(manager, ilk, address(this));
                lockGemAndDraw(manager, jug, gemJoin, daiJoin, cdp, wadC, wadD, transferFrom);
            }
        
            function openLockGNTAndDraw(
                address manager,
                address jug,
                address gntJoin,
                address daiJoin,
                bytes32 ilk,
                uint wadC,
                uint wadD
            ) public returns (address bag, uint cdp) {
                // Creates bag (if doesn't exist) to hold GNT
                bag = GNTJoinLike(gntJoin).bags(address(this));
                if (bag == address(0)) {
                    bag = makeGemBag(gntJoin);
                }
                // Transfer funds to the funds which previously were sent to the proxy
                GemLike(GemJoinLike(gntJoin).gem()).transfer(bag, wadC);
                cdp = openLockGemAndDraw(manager, jug, gntJoin, daiJoin, ilk, wadC, wadD, false);
            }
        
            function wipeAndFreeETH(
                address manager,
                address ethJoin,
                address daiJoin,
                uint cdp,
                uint wadC,
                uint wadD
            ) public {
                address urn = ManagerLike(manager).urns(cdp);
                // Joins DAI amount into the vat
                daiJoin_join(daiJoin, urn, wadD);
                // Paybacks debt to the CDP and unlocks WETH amount from it
                frob(
                    manager,
                    cdp,
                    -toInt(wadC),
                    _getWipeDart(ManagerLike(manager).vat(), VatLike(ManagerLike(manager).vat()).dai(urn), urn, ManagerLike(manager).ilks(cdp))
                );
                // Moves the amount from the CDP urn to proxy's address
                flux(manager, cdp, address(this), wadC);
                // Exits WETH amount to proxy address as a token
                GemJoinLike(ethJoin).exit(address(this), wadC);
                // Converts WETH to ETH
                GemJoinLike(ethJoin).gem().withdraw(wadC);
                // Sends ETH back to the user's wallet
                msg.sender.transfer(wadC);
            }
        
            function wipeAllAndFreeETH(
                address manager,
                address ethJoin,
                address daiJoin,
                uint cdp,
                uint wadC
            ) public {
                address vat = ManagerLike(manager).vat();
                address urn = ManagerLike(manager).urns(cdp);
                bytes32 ilk = ManagerLike(manager).ilks(cdp);
                (, uint art) = VatLike(vat).urns(ilk, urn);
        
                // Joins DAI amount into the vat
                daiJoin_join(daiJoin, urn, _getWipeAllWad(vat, urn, urn, ilk));
                // Paybacks debt to the CDP and unlocks WETH amount from it
                frob(
                    manager,
                    cdp,
                    -toInt(wadC),
                    -int(art)
                );
                // Moves the amount from the CDP urn to proxy's address
                flux(manager, cdp, address(this), wadC);
                // Exits WETH amount to proxy address as a token
                GemJoinLike(ethJoin).exit(address(this), wadC);
                // Converts WETH to ETH
                GemJoinLike(ethJoin).gem().withdraw(wadC);
                // Sends ETH back to the user's wallet
                msg.sender.transfer(wadC);
            }
        
            function wipeAndFreeGem(
                address manager,
                address gemJoin,
                address daiJoin,
                uint cdp,
                uint wadC,
                uint wadD
            ) public {
                address urn = ManagerLike(manager).urns(cdp);
                // Joins DAI amount into the vat
                daiJoin_join(daiJoin, urn, wadD);
                uint wad18 = convertTo18(gemJoin, wadC);
                // Paybacks debt to the CDP and unlocks token amount from it
                frob(
                    manager,
                    cdp,
                    -toInt(wad18),
                    _getWipeDart(ManagerLike(manager).vat(), VatLike(ManagerLike(manager).vat()).dai(urn), urn, ManagerLike(manager).ilks(cdp))
                );
                // Moves the amount from the CDP urn to proxy's address
                flux(manager, cdp, address(this), wad18);
                // Exits token amount to the user's wallet as a token
                GemJoinLike(gemJoin).exit(msg.sender, wadC);
            }
        
            function wipeAllAndFreeGem(
                address manager,
                address gemJoin,
                address daiJoin,
                uint cdp,
                uint wadC
            ) public {
                address vat = ManagerLike(manager).vat();
                address urn = ManagerLike(manager).urns(cdp);
                bytes32 ilk = ManagerLike(manager).ilks(cdp);
                (, uint art) = VatLike(vat).urns(ilk, urn);
        
                // Joins DAI amount into the vat
                daiJoin_join(daiJoin, urn, _getWipeAllWad(vat, urn, urn, ilk));
                uint wad18 = convertTo18(gemJoin, wadC);
                // Paybacks debt to the CDP and unlocks token amount from it
                frob(
                    manager,
                    cdp,
                    -toInt(wad18),
                    -int(art)
                );
                // Moves the amount from the CDP urn to proxy's address
                flux(manager, cdp, address(this), wad18);
                // Exits token amount to the user's wallet as a token
                GemJoinLike(gemJoin).exit(msg.sender, wadC);
            }
        }
        
        contract DssProxyActionsEnd is Common {
            // Internal functions
        
            function _free(
                address manager,
                address end,
                uint cdp
            ) internal returns (uint ink) {
                bytes32 ilk = ManagerLike(manager).ilks(cdp);
                address urn = ManagerLike(manager).urns(cdp);
                VatLike vat = VatLike(ManagerLike(manager).vat());
                uint art;
                (ink, art) = vat.urns(ilk, urn);
        
                // If CDP still has debt, it needs to be paid
                if (art > 0) {
                    EndLike(end).skim(ilk, urn);
                    (ink,) = vat.urns(ilk, urn);
                }
                // Approves the manager to transfer the position to proxy's address in the vat
                if (vat.can(address(this), address(manager)) == 0) {
                    vat.hope(manager);
                }
                // Transfers position from CDP to the proxy address
                ManagerLike(manager).quit(cdp, address(this));
                // Frees the position and recovers the collateral in the vat registry
                EndLike(end).free(ilk);
            }
        
            // Public functions
            function freeETH(
                address manager,
                address ethJoin,
                address end,
                uint cdp
            ) public {
                uint wad = _free(manager, end, cdp);
                // Exits WETH amount to proxy address as a token
                GemJoinLike(ethJoin).exit(address(this), wad);
                // Converts WETH to ETH
                GemJoinLike(ethJoin).gem().withdraw(wad);
                // Sends ETH back to the user's wallet
                msg.sender.transfer(wad);
            }
        
            function freeGem(
                address manager,
                address gemJoin,
                address end,
                uint cdp
            ) public {
                uint wad = _free(manager, end, cdp);
                // Exits token amount to the user's wallet as a token
                GemJoinLike(gemJoin).exit(msg.sender, wad);
            }
        
            function pack(
                address daiJoin,
                address end,
                uint wad
            ) public {
                daiJoin_join(daiJoin, address(this), wad);
                VatLike vat = DaiJoinLike(daiJoin).vat();
                // Approves the end to take out DAI from the proxy's balance in the vat
                if (vat.can(address(this), address(end)) == 0) {
                    vat.hope(end);
                }
                EndLike(end).pack(wad);
            }
        
            function cashETH(
                address ethJoin,
                address end,
                bytes32 ilk,
                uint wad
            ) public {
                EndLike(end).cash(ilk, wad);
                uint wadC = mul(wad, EndLike(end).fix(ilk)) / RAY;
                // Exits WETH amount to proxy address as a token
                GemJoinLike(ethJoin).exit(address(this), wadC);
                // Converts WETH to ETH
                GemJoinLike(ethJoin).gem().withdraw(wadC);
                // Sends ETH back to the user's wallet
                msg.sender.transfer(wadC);
            }
        
            function cashGem(
                address gemJoin,
                address end,
                bytes32 ilk,
                uint wad
            ) public {
                EndLike(end).cash(ilk, wad);
                // Exits token amount to the user's wallet as a token
                GemJoinLike(gemJoin).exit(msg.sender, mul(wad, EndLike(end).fix(ilk)) / RAY);
            }
        }
        
        contract DssProxyActionsDsr is Common {
            function join(
                address daiJoin,
                address pot,
                uint wad
            ) public {
                VatLike vat = DaiJoinLike(daiJoin).vat();
                // Executes drip to get the chi rate updated to rho == now, otherwise join will fail
                uint chi = PotLike(pot).drip();
                // Joins wad amount to the vat balance
                daiJoin_join(daiJoin, address(this), wad);
                // Approves the pot to take out DAI from the proxy's balance in the vat
                if (vat.can(address(this), address(pot)) == 0) {
                    vat.hope(pot);
                }
                // Joins the pie value (equivalent to the DAI wad amount) in the pot
                PotLike(pot).join(mul(wad, RAY) / chi);
            }
        
            function exit(
                address daiJoin,
                address pot,
                uint wad
            ) public {
                VatLike vat = DaiJoinLike(daiJoin).vat();
                // Executes drip to count the savings accumulated until this moment
                uint chi = PotLike(pot).drip();
                // Calculates the pie value in the pot equivalent to the DAI wad amount
                uint pie = mul(wad, RAY) / chi;
                // Exits DAI from the pot
                PotLike(pot).exit(pie);
                // Checks the actual balance of DAI in the vat after the pot exit
                uint bal = DaiJoinLike(daiJoin).vat().dai(address(this));
                // Allows adapter to access to proxy's DAI balance in the vat
                if (vat.can(address(this), address(daiJoin)) == 0) {
                    vat.hope(daiJoin);
                }
                // It is necessary to check if due rounding the exact wad amount can be exited by the adapter.
                // Otherwise it will do the maximum DAI balance in the vat
                DaiJoinLike(daiJoin).exit(
                    msg.sender,
                    bal >= mul(wad, RAY) ? wad : bal / RAY
                );
            }
        
            function exitAll(
                address daiJoin,
                address pot
            ) public {
                VatLike vat = DaiJoinLike(daiJoin).vat();
                // Executes drip to count the savings accumulated until this moment
                uint chi = PotLike(pot).drip();
                // Gets the total pie belonging to the proxy address
                uint pie = PotLike(pot).pie(address(this));
                // Exits DAI from the pot
                PotLike(pot).exit(pie);
                // Allows adapter to access to proxy's DAI balance in the vat
                if (vat.can(address(this), address(daiJoin)) == 0) {
                    vat.hope(daiJoin);
                }
                // Exits the DAI amount corresponding to the value of pie
                DaiJoinLike(daiJoin).exit(msg.sender, mul(chi, pie) / RAY);
            }
        }

        File 6 of 6: DssCdpManager
        // hevm: flattened sources of /nix/store/jyvwn5yyqxwkfxc45k04h2dk209dn6sh-dss-cdp-manager-8976239/src/DssCdpManager.sol
        pragma solidity =0.5.12;
        
        ////// /nix/store/4vip6nyqfd0yhs15md21rzxsk5jgx6sv-dss/dapp/dss/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/jyvwn5yyqxwkfxc45k04h2dk209dn6sh-dss-cdp-manager-8976239/src/DssCdpManager.sol
        /* pragma solidity 0.5.12; */
        
        /* import { LibNote } from "dss/lib.sol"; */
        
        contract VatLike {
            function urns(bytes32, address) public view returns (uint, uint);
            function hope(address) public;
            function flux(bytes32, address, address, uint) public;
            function move(address, address, uint) public;
            function frob(bytes32, address, address, address, int, int) public;
            function fork(bytes32, address, address, int, int) public;
        }
        
        contract UrnHandler {
            constructor(address vat) public {
                VatLike(vat).hope(msg.sender);
            }
        }
        
        contract DssCdpManager is LibNote {
            address                   public vat;
            uint                      public cdpi;      // Auto incremental
            mapping (uint => address) public urns;      // CDPId => UrnHandler
            mapping (uint => List)    public list;      // CDPId => Prev & Next CDPIds (double linked list)
            mapping (uint => address) public owns;      // CDPId => Owner
            mapping (uint => bytes32) public ilks;      // CDPId => Ilk
        
            mapping (address => uint) public first;     // Owner => First CDPId
            mapping (address => uint) public last;      // Owner => Last CDPId
            mapping (address => uint) public count;     // Owner => Amount of CDPs
        
            mapping (
                address => mapping (
                    uint => mapping (
                        address => uint
                    )
                )
            ) public cdpCan;                            // Owner => CDPId => Allowed Addr => True/False
        
            mapping (
                address => mapping (
                    address => uint
                )
            ) public urnCan;                            // Urn => Allowed Addr => True/False
        
            struct List {
                uint prev;
                uint next;
            }
        
            event NewCdp(address indexed usr, address indexed own, uint indexed cdp);
        
            modifier cdpAllowed(
                uint cdp
            ) {
                require(msg.sender == owns[cdp] || cdpCan[owns[cdp]][cdp][msg.sender] == 1, "cdp-not-allowed");
                _;
            }
        
            modifier urnAllowed(
                address urn
            ) {
                require(msg.sender == urn || urnCan[urn][msg.sender] == 1, "urn-not-allowed");
                _;
            }
        
            constructor(address vat_) public {
                vat = vat_;
            }
        
            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);
            }
        
            function toInt(uint x) internal pure returns (int y) {
                y = int(x);
                require(y >= 0);
            }
        
            // Allow/disallow a usr address to manage the cdp.
            function cdpAllow(
                uint cdp,
                address usr,
                uint ok
            ) public cdpAllowed(cdp) {
                cdpCan[owns[cdp]][cdp][usr] = ok;
            }
        
            // Allow/disallow a usr address to quit to the the sender urn.
            function urnAllow(
                address usr,
                uint ok
            ) public {
                urnCan[msg.sender][usr] = ok;
            }
        
            // Open a new cdp for a given usr address.
            function open(
                bytes32 ilk,
                address usr
            ) public note returns (uint) {
                require(usr != address(0), "usr-address-0");
        
                cdpi = add(cdpi, 1);
                urns[cdpi] = address(new UrnHandler(vat));
                owns[cdpi] = usr;
                ilks[cdpi] = ilk;
        
                // Add new CDP to double linked list and pointers
                if (first[usr] == 0) {
                    first[usr] = cdpi;
                }
                if (last[usr] != 0) {
                    list[cdpi].prev = last[usr];
                    list[last[usr]].next = cdpi;
                }
                last[usr] = cdpi;
                count[usr] = add(count[usr], 1);
        
                emit NewCdp(msg.sender, usr, cdpi);
                return cdpi;
            }
        
            // Give the cdp ownership to a dst address.
            function give(
                uint cdp,
                address dst
            ) public note cdpAllowed(cdp) {
                require(dst != address(0), "dst-address-0");
                require(dst != owns[cdp], "dst-already-owner");
        
                // Remove transferred CDP from double linked list of origin user and pointers
                if (list[cdp].prev != 0) {
                    list[list[cdp].prev].next = list[cdp].next;         // Set the next pointer of the prev cdp (if exists) to the next of the transferred one
                }
                if (list[cdp].next != 0) {                              // If wasn't the last one
                    list[list[cdp].next].prev = list[cdp].prev;         // Set the prev pointer of the next cdp to the prev of the transferred one
                } else {                                                // If was the last one
                    last[owns[cdp]] = list[cdp].prev;                   // Update last pointer of the owner
                }
                if (first[owns[cdp]] == cdp) {                          // If was the first one
                    first[owns[cdp]] = list[cdp].next;                  // Update first pointer of the owner
                }
                count[owns[cdp]] = sub(count[owns[cdp]], 1);
        
                // Transfer ownership
                owns[cdp] = dst;
        
                // Add transferred CDP to double linked list of destiny user and pointers
                list[cdp].prev = last[dst];
                list[cdp].next = 0;
                if (last[dst] != 0) {
                    list[last[dst]].next = cdp;
                }
                if (first[dst] == 0) {
                    first[dst] = cdp;
                }
                last[dst] = cdp;
                count[dst] = add(count[dst], 1);
            }
        
            // Frob the cdp keeping the generated DAI or collateral freed in the cdp urn address.
            function frob(
                uint cdp,
                int dink,
                int dart
            ) public note cdpAllowed(cdp) {
                address urn = urns[cdp];
                VatLike(vat).frob(
                    ilks[cdp],
                    urn,
                    urn,
                    urn,
                    dink,
                    dart
                );
            }
        
            // Transfer wad amount of cdp collateral from the cdp address to a dst address.
            function flux(
                uint cdp,
                address dst,
                uint wad
            ) public note cdpAllowed(cdp) {
                VatLike(vat).flux(ilks[cdp], urns[cdp], dst, wad);
            }
        
            // Transfer wad amount of any type of collateral (ilk) from the cdp address to a dst address.
            // This function has the purpose to take away collateral from the system that doesn't correspond to the cdp but was sent there wrongly.
            function flux(
                bytes32 ilk,
                uint cdp,
                address dst,
                uint wad
            ) public note cdpAllowed(cdp) {
                VatLike(vat).flux(ilk, urns[cdp], dst, wad);
            }
        
            // Transfer wad amount of DAI from the cdp address to a dst address.
            function move(
                uint cdp,
                address dst,
                uint rad
            ) public note cdpAllowed(cdp) {
                VatLike(vat).move(urns[cdp], dst, rad);
            }
        
            // Quit the system, migrating the cdp (ink, art) to a different dst urn
            function quit(
                uint cdp,
                address dst
            ) public note cdpAllowed(cdp) urnAllowed(dst) {
                (uint ink, uint art) = VatLike(vat).urns(ilks[cdp], urns[cdp]);
                VatLike(vat).fork(
                    ilks[cdp],
                    urns[cdp],
                    dst,
                    toInt(ink),
                    toInt(art)
                );
            }
        
            // Import a position from src urn to the urn owned by cdp
            function enter(
                address src,
                uint cdp
            ) public note urnAllowed(src) cdpAllowed(cdp) {
                (uint ink, uint art) = VatLike(vat).urns(ilks[cdp], src);
                VatLike(vat).fork(
                    ilks[cdp],
                    src,
                    urns[cdp],
                    toInt(ink),
                    toInt(art)
                );
            }
        
            // Move a position from cdpSrc urn to the cdpDst urn
            function shift(
                uint cdpSrc,
                uint cdpDst
            ) public note cdpAllowed(cdpSrc) cdpAllowed(cdpDst) {
                require(ilks[cdpSrc] == ilks[cdpDst], "non-matching-cdps");
                (uint ink, uint art) = VatLike(vat).urns(ilks[cdpSrc], urns[cdpSrc]);
                VatLike(vat).fork(
                    ilks[cdpSrc],
                    urns[cdpSrc],
                    urns[cdpDst],
                    toInt(ink),
                    toInt(art)
                );
            }
        }