From d457d3ae8f66b90e78e3693a1a84a1f40cdc6387 Mon Sep 17 00:00:00 2001
From: Sowmayjain <champ.sowmay@gmail.com>
Date: Fri, 29 Mar 2019 03:56:52 +0530
Subject: [PATCH] Completed InstaMaker (untested)

---
 contracts/ProxyLogics/InstaMaker.sol    | 346 ++++++++++++++----------
 contracts/ProxyLogics/MakerContract.sol | 288 ++++++++++++++++++++
 2 files changed, 493 insertions(+), 141 deletions(-)
 create mode 100644 contracts/ProxyLogics/MakerContract.sol

diff --git a/contracts/ProxyLogics/InstaMaker.sol b/contracts/ProxyLogics/InstaMaker.sol
index 4218731..89da4eb 100644
--- a/contracts/ProxyLogics/InstaMaker.sol
+++ b/contracts/ProxyLogics/InstaMaker.sol
@@ -21,6 +21,34 @@ library SafeMath {
 }
 
 
+contract DSMath {
+
+    function add(uint x, uint y) internal pure returns (uint z) {
+        require((z = x + y) >= x, "math-not-safe");
+    }
+
+    function mul(uint x, uint y) internal pure returns (uint z) {
+        require(y == 0 || (z = x * y) / y == x, "math-not-safe");
+    }
+
+    uint constant WAD = 10 ** 18;
+    uint constant RAY = 10 ** 27;
+
+    function rmul(uint x, uint y) internal pure returns (uint z) {
+        z = add(mul(x, y), RAY / 2) / RAY;
+    }
+
+    function rdiv(uint x, uint y) internal pure returns (uint z) {
+        z = add(mul(x, RAY), y / 2) / y;
+    }
+
+    function wdiv(uint x, uint y) internal pure returns (uint z) {
+        z = add(mul(x, WAD), y / 2) / y;
+    }
+
+}
+
+
 contract IERC20 {
     function balanceOf(address who) external view returns (uint256);
     function transfer(address to, uint256 value) external returns (bool);
@@ -29,22 +57,43 @@ contract IERC20 {
 }
 
 
-contract MakerCDP {
-    function open() external returns (bytes32 cup);
-    function join(uint wad) external; // Join PETH
-    function exit(uint wad) external; // Exit PETH
-    function give(bytes32 cup, address guy) external;
-    function lock(bytes32 cup, uint wad) external;
-    function free(bytes32 cup, uint wad) external;
-    function draw(bytes32 cup, uint wad) external;
-    function wipe(bytes32 cup, uint wad) external;
-    function per() external view returns (uint ray);
-    function lad(bytes32 cup) external view returns (address);
+contract TubInterface {
+    function open() public returns (bytes32);
+    function join(uint) public;
+    function exit(uint) public;
+    function lock(bytes32, uint) public;
+    function free(bytes32, uint) public;
+    function draw(bytes32, uint) public;
+    function wipe(bytes32, uint) public;
+    function give(bytes32, address) public;
+    function shut(bytes32) public;
+    function cups(bytes32) public view returns (address, uint, uint, uint);
+    function gem() public view returns (TokenInterface);
+    function gov() public view returns (TokenInterface);
+    function skr() public view returns (TokenInterface);
+    function sai() public view returns (TokenInterface);
+    function mat() public view returns (uint);
+    function ink(bytes32) public view returns (uint);
+    function tab(bytes32) public view returns (uint);
+    function rap(bytes32) public view returns (uint);
+    function per() public view returns (uint);
+    function pep() public view returns (PepInterface);
 }
 
 
-contract PriceInterface {
-    function peek() external view returns (bytes32, bool);
+contract TokenInterface {
+    function allowance(address, address) public view returns (uint);
+    function balanceOf(address) public view returns (uint);
+    function approve(address, uint) public;
+    function transfer(address, uint) public returns (bool);
+    function transferFrom(address, address, uint) public returns (bool);
+    function deposit() public payable;
+    function withdraw(uint) public;
+}
+
+
+contract PepInterface {
+    function peek() public returns (bytes32, bool);
 }
 
 
@@ -54,160 +103,175 @@ contract WETHFace {
 }
 
 
-contract Helpers {
+contract Helpers is DSMath {
 
     using SafeMath for uint;
     using SafeMath for uint256;
 
-    function getETHRate() public view returns (uint) {
-        PriceInterface ethRate = PriceInterface(getAddress("ethfeed"));
-        bytes32 ethrate;
-        (ethrate, ) = ethRate.peek();
+    /**
+     * @dev get MakerDAO CDP engine
+     */
+    function getPriceFeedAddress() public pure returns (address eth) {
+        eth = 0x729D19f657BD0614b4985Cf1D82531c67569197B;
+    }
+
+    /**
+     * @dev get ETH price feed
+     */
+    function getSaiTubAddress() public pure returns (address sai) {
+        sai = 0x448a5065aeBB8E423F0896E6c5D525C040f59af3;
+    }
+
+    /**
+     * @dev get uniswap MKR/DAI exchange
+     */
+    function getUniswapMKRExchange() public pure returns (address ume) {
+        ume = 0x2C4Bd064b998838076fa341A83d007FC2FA50957;
+    }
+
+    /**
+     * @dev get admin address
+     */
+    function getAddressAdmin() public pure returns (address admin) {
+        admin = 0x7284a8451d9a0e7Dc62B3a71C0593eA2eC5c5638;
+    }
+
+    /**
+     * @dev get onchain ethereum price
+     */
+    function getRate() public returns (uint) {
+        (bytes32 ethrate, ) = PepInterface(getPriceFeedAddress()).peek();
         return uint(ethrate);
     }
 
-    function getCDP(address borrower) public view returns (uint, bytes32) {
-        return (uint(cdps[borrower]), cdps[borrower]);
-    }
-
-    function approveERC20() public {
-        IERC20 wethTkn = IERC20(getAddress("weth"));
-        wethTkn.approve(cdpAddr, 2**256 - 1);
-        IERC20 pethTkn = IERC20(getAddress("peth"));
-        pethTkn.approve(cdpAddr, 2**256 - 1);
-        IERC20 mkrTkn = IERC20(getAddress("mkr"));
-        mkrTkn.approve(cdpAddr, 2**256 - 1);
-        IERC20 daiTkn = IERC20(getAddress("dai"));
-        daiTkn.approve(cdpAddr, 2**256 - 1);
-    }
-
-
-}
-
-
-contract IssueLoan is Helpers {
-
-    event LockedETH(address borrower, uint lockETH, uint lockPETH, address lockedBy);
-    event LoanedDAI(address borrower, uint loanDAI, address payTo);
-    event NewCDP(address borrower, bytes32 cdpBytes);
-
-    function pethPEReth(uint ethNum) public view returns (uint rPETH) {
-        MakerCDP loanMaster = MakerCDP(cdpAddr);
-        rPETH = (ethNum.mul(10 ** 27)).div(loanMaster.per());
-    }
-
-    function borrow(uint daiDraw, address beneficiary) public payable {
-        if (msg.value > 0) {lockETH(msg.sender);}
-        if (daiDraw > 0) {drawDAI(daiDraw, beneficiary);}
-    }
-
-    function lockETH(address borrower) public payable {
-        MakerCDP loanMaster = MakerCDP(cdpAddr);
-        if (cdps[borrower] == blankCDP) {
-            require(msg.sender == borrower, "Creating CDP for others is not permitted at the moment.");
-            cdps[msg.sender] = loanMaster.open();
-            emit NewCDP(msg.sender, cdps[msg.sender]);
+    /**
+     * @dev handling stability fees payment
+     */
+    function handleGovFee(TubInterface tub, uint saiDebtFee) internal {
+        address _otc = getUniswapMKRExchange();
+        (bytes32 val, bool ok) = tub.pep().peek();
+        if (ok && val != 0) {
+            uint govAmt = wdiv(saiDebtFee, uint(val)); // Fees in MKR
+            uint saiGovAmt = govAmt; // (SAMYAK) // get DAI required govAmt (MKR) from UniSwap => {saiGovAmt} not equals to {govAmt}
+            if (tub.sai().allowance(address(this), _otc) != uint(-1)) {
+                tub.sai().approve(_otc, uint(-1));
+            }
+            tub.sai().transferFrom(msg.sender, address(this), saiGovAmt);
+            // (SAMYAK) // swap DAI with MKR from uniswap
         }
-        WETHFace wethTkn = WETHFace(getAddress("weth"));
-        wethTkn.deposit.value(msg.value)(); // ETH to WETH
-        uint pethToLock = pethPEReth(msg.value);
-        loanMaster.join(pethToLock); // WETH to PETH
-        loanMaster.lock(cdps[borrower], pethToLock); // PETH to CDP
-        emit LockedETH(
-            borrower, msg.value, pethToLock, msg.sender
-        );
-    }
-
-    function drawDAI(uint daiDraw, address beneficiary) public {
-        require(!freezed, "Operation Disabled");
-        MakerCDP loanMaster = MakerCDP(cdpAddr);
-        loanMaster.draw(cdps[msg.sender], daiDraw);
-        IERC20 daiTkn = IERC20(getAddress("dai"));
-        address payTo = msg.sender;
-        if (payTo != address(0)) {
-            payTo = beneficiary;
-        }
-        daiTkn.transfer(payTo, daiDraw);
-        emit LoanedDAI(msg.sender, daiDraw, payTo);
     }
 
 }
 
 
-contract RepayLoan is IssueLoan {
+contract CDPResolver is Helpers {
 
-    event WipedDAI(address borrower, uint daiWipe, uint mkrCharged, address wipedBy);
-    event UnlockedETH(address borrower, uint ethFree);
-
-    function repay(uint daiWipe, uint ethFree) public payable {
-        if (daiWipe > 0) {wipeDAI(daiWipe, msg.sender);}
-        if (ethFree > 0) {unlockETH(ethFree);}
+    function open() public returns (bytes32) {
+        return TubInterface(getSaiTubAddress()).open();
     }
 
-    function wipeDAI(uint daiWipe, address borrower) public payable {
-        address dai = getAddress("dai");
-        address mkr = getAddress("mkr");
-        address eth = getAddress("eth");
-
-        IERC20 daiTkn = IERC20(dai);
-        IERC20 mkrTkn = IERC20(mkr);
-
-        uint contractMKR = mkrTkn.balanceOf(address(this)); // contract MKR balance before wiping
-        daiTkn.transferFrom(msg.sender, address(this), daiWipe); // get DAI to pay the debt
-        MakerCDP loanMaster = MakerCDP(cdpAddr);
-        loanMaster.wipe(cdps[borrower], daiWipe); // wipe DAI
-        uint mkrCharged = contractMKR - mkrTkn.balanceOf(address(this)); // MKR fee = before wiping bal - after wiping bal
-
-        // claiming paid MKR back
-        if (msg.value > 0) { // Interacting with Kyber to swap ETH with MKR
-            swapETHMKR(
-                eth, mkr, mkrCharged, msg.value
-            );
-        } else { // take MKR directly from address
-            mkrTkn.transferFrom(msg.sender, address(this), mkrCharged); // user paying MKR fees
-        }
-
-        emit WipedDAI(
-            borrower, daiWipe, mkrCharged, msg.sender
-        );
+    function give(uint cdpNum, address nextOwner) public {
+        TubInterface(getSaiTubAddress()).give(bytes32(cdpNum), nextOwner);
     }
 
-    function unlockETH(uint ethFree) public {
-        require(!freezed, "Operation Disabled");
-        uint pethToUnlock = pethPEReth(ethFree);
-        MakerCDP loanMaster = MakerCDP(cdpAddr);
-        loanMaster.free(cdps[msg.sender], pethToUnlock); // CDP to PETH
-        loanMaster.exit(pethToUnlock); // PETH to WETH
-        WETHFace wethTkn = WETHFace(getAddress("weth"));
-        wethTkn.withdraw(ethFree); // WETH to ETH
-        msg.sender.transfer(ethFree);
-        emit UnlockedETH(msg.sender, ethFree);
-    }
+    function lock(uint cdpNum) public payable {
+        bytes32 cup = bytes32(cdpNum);
+        address tubAddr = getSaiTubAddress();
+        if (msg.value > 0) {
+            TubInterface tub = TubInterface(tubAddr);
 
-    function swapETHMKR(
-        address eth,
-        address mkr,
-        uint mkrCharged,
-        uint ethQty
-    ) internal 
-    {
-        InstaKyber instak = InstaKyber(getAddress("InstaKyber"));
-        uint minRate;
-        (, minRate) = instak.getExpectedPrice(eth, mkr, ethQty);
-        uint mkrBought = instak.executeTrade.value(ethQty)(
-            eth, mkr, ethQty, minRate, mkrCharged
-        );
-        require(mkrCharged == mkrBought, "ETH not sufficient to cover the MKR fees.");
-        if (address(this).balance > 0) {
-            msg.sender.transfer(address(this).balance);
+            (address lad,,,) = tub.cups(cup);
+            require(lad == address(this), "cup-not-owned");
+
+            tub.gem().deposit.value(msg.value)();
+
+            uint ink = rdiv(msg.value, tub.per());
+            ink = rmul(ink, tub.per()) <= msg.value ? ink : ink - 1;
+
+            if (tub.gem().allowance(address(this), tubAddr) != uint(-1)) {
+                tub.gem().approve(tubAddr, uint(-1));
+            }
+            tub.join(ink);
+
+            if (tub.skr().allowance(address(this), tubAddr) != uint(-1)) {
+                tub.skr().approve(tubAddr, uint(-1));
+            }
+            tub.lock(cup, ink);
         }
     }
 
+    function draw(uint cdpNum, uint wad) public {
+        bytes32 cup = bytes32(cdpNum);
+        if (wad > 0) {
+            TubInterface tub = TubInterface(getSaiTubAddress());
+            tub.draw(cup, wad);
+            tub.sai().transfer(msg.sender, wad);
+        }
+    }
 
+    function wipe(uint cdpNum, uint wad) public {
+        bytes32 cup = bytes32(cdpNum);
+        address tubAddr = getSaiTubAddress();
+        if (wad > 0) {
+            TubInterface tub = TubInterface(tubAddr);
+
+            tub.sai().transferFrom(msg.sender, address(this), wad);
+            handleGovFee(tub, rmul(wad, rdiv(tub.rap(cup), tub.tab(cup))));
+
+            if (tub.sai().allowance(address(this), tubAddr) != uint(-1)) {
+                tub.sai().approve(tubAddr, uint(-1));
+            }
+            if (tub.gov().allowance(address(this), tubAddr) != uint(-1)) {
+                tub.gov().approve(tubAddr, uint(-1));
+            }
+            tub.wipe(cup, wad);
+        }
+    }
+
+    function free(uint cdpNum, uint jam) public {
+        bytes32 cup = bytes32(cdpNum);
+        address tubAddr = getSaiTubAddress();
+        if (jam > 0) {
+            TubInterface tub = TubInterface(tubAddr);
+            uint ink = rdiv(jam, tub.per());
+            ink = rmul(ink, tub.per()) <= jam ? ink : ink - 1;
+            tub.free(cup, ink);
+            if (tub.skr().allowance(address(this), tubAddr) != uint(-1)) {
+                tub.skr().approve(tubAddr, uint(-1));
+            }
+            tub.exit(ink);
+            uint freeJam = tub.gem().balanceOf(address(this)); // Withdraw possible previous stuck WETH as well
+            tub.gem().withdraw(freeJam);
+            address(msg.sender).transfer(freeJam);
+        }
+    }
 
 }
 
-contract InstaMaker is BorrowTasks {
+
+contract CDPCluster is CDPResolver {
+
+    function wipeAndFree(uint cdpNum, uint jam, uint wad) public payable {
+        wipe(cdpNum, wad);
+        free(cdpNum, jam);
+    }
+
+    function shut(uint cdpNum) public {
+        bytes32 cup = bytes32(cdpNum);
+        TubInterface tub = TubInterface(getSaiTubAddress());
+        wipeAndFree(cdpNum, rmul(tub.ink(cup), tub.per()), tub.tab(cup));
+        tub.shut(cup);
+    }
+
+    function openAndLock() public payable returns (bytes32 cup) {
+        cup = open();
+        lock(uint(cup));
+    }
+
+}
+
+
+contract InstaMaker is CDPResolver {
 
     uint public version;
     
diff --git a/contracts/ProxyLogics/MakerContract.sol b/contracts/ProxyLogics/MakerContract.sol
new file mode 100644
index 0000000..73e013f
--- /dev/null
+++ b/contracts/ProxyLogics/MakerContract.sol
@@ -0,0 +1,288 @@
+pragma solidity ^0.4.23;
+
+/// math.sol -- mixin for inline numerical wizardry
+
+// 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.13;
+
+contract DSMath {
+    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);
+    }
+
+    function min(uint x, uint y) internal pure returns (uint z) {
+        return x <= y ? x : y;
+    }
+    function max(uint x, uint y) internal pure returns (uint z) {
+        return x >= y ? x : y;
+    }
+    function imin(int x, int y) internal pure returns (int z) {
+        return x <= y ? x : y;
+    }
+    function imax(int x, int y) internal pure returns (int z) {
+        return x >= y ? x : y;
+    }
+
+    uint constant WAD = 10 ** 18;
+    uint constant RAY = 10 ** 27;
+
+    function wmul(uint x, uint y) internal pure returns (uint z) {
+        z = add(mul(x, y), WAD / 2) / WAD;
+    }
+    function rmul(uint x, uint y) internal pure returns (uint z) {
+        z = add(mul(x, y), RAY / 2) / RAY;
+    }
+    function wdiv(uint x, uint y) internal pure returns (uint z) {
+        z = add(mul(x, WAD), y / 2) / y;
+    }
+    function rdiv(uint x, uint y) internal pure returns (uint z) {
+        z = add(mul(x, RAY), y / 2) / y;
+    }
+
+    // This famous algorithm is called "exponentiation by squaring"
+    // and calculates x^n with x as fixed-point and n as regular unsigned.
+    //
+    // It's O(log n), instead of O(n) for naive repeated multiplication.
+    //
+    // These facts are why it works:
+    //
+    //  If n is even, then x^n = (x^2)^(n/2).
+    //  If n is odd,  then x^n = x * x^(n-1),
+    //   and applying the equation for even x gives
+    //    x^n = x * (x^2)^((n-1) / 2).
+    //
+    //  Also, EVM division is flooring and
+    //    floor[(n-1) / 2] = floor[n / 2].
+    //
+    function rpow(uint x, uint n) internal pure returns (uint z) {
+        z = n % 2 != 0 ? x : RAY;
+
+        for (n /= 2; n != 0; n /= 2) {
+            x = rmul(x, x);
+
+            if (n % 2 != 0) {
+                z = rmul(z, x);
+            }
+        }
+    }
+}
+
+contract TubInterface {
+    function open() public returns (bytes32);
+    function join(uint) public;
+    function exit(uint) public;
+    function lock(bytes32, uint) public;
+    function free(bytes32, uint) public;
+    function draw(bytes32, uint) public;
+    function wipe(bytes32, uint) public;
+    function give(bytes32, address) public;
+    function shut(bytes32) public;
+    function cups(bytes32) public view returns (address, uint, uint, uint);
+    function gem() public view returns (TokenInterface);
+    function gov() public view returns (TokenInterface);
+    function skr() public view returns (TokenInterface);
+    function sai() public view returns (TokenInterface);
+    function mat() public view returns (uint);
+    function ink(bytes32) public view returns (uint);
+    function tab(bytes32) public view returns (uint);
+    function rap(bytes32) public view returns (uint);
+    function per() public view returns (uint);
+    function pep() public view returns (PepInterface);
+}
+
+contract TokenInterface {
+    function allowance(address, address) public view returns (uint);
+    function balanceOf(address) public view returns (uint);
+    function approve(address, uint) public;
+    function transfer(address, uint) public returns (bool);
+    function transferFrom(address, address, uint) public returns (bool);
+    function deposit() public payable;
+    function withdraw(uint) public;
+}
+
+contract PepInterface {
+    function peek() public returns (bytes32, bool);
+}
+
+contract OtcInterface {
+    function getPayAmount(address, address, uint) public view returns (uint);
+    function buyAllAmount(address, uint, address pay_gem, uint) public returns (uint);
+}
+
+contract SaiProxy is DSMath {
+    function open(address tub_) public returns (bytes32) {
+        return TubInterface(tub_).open();
+    }
+
+    function give(address tub_, bytes32 cup, address lad) public {
+        TubInterface(tub_).give(cup, lad);
+    }
+
+    function lock(address tub_, bytes32 cup) public payable {
+        if (msg.value > 0) {
+            TubInterface tub = TubInterface(tub_);
+
+            (address lad,,,) = tub.cups(cup);
+            require(lad == address(this), "cup-not-owned");
+
+            tub.gem().deposit.value(msg.value)();
+
+            uint ink = rdiv(msg.value, tub.per());
+            ink = rmul(ink, tub.per()) <= msg.value ? ink : ink - 1;
+
+            if (tub.gem().allowance(this, tub) != uint(-1)) {
+                tub.gem().approve(tub, uint(-1));
+            }
+            tub.join(ink);
+
+            if (tub.skr().allowance(this, tub) != uint(-1)) {
+                tub.skr().approve(tub, uint(-1));
+            }
+            tub.lock(cup, ink);
+        }
+    }
+
+    function draw(address tub_, bytes32 cup, uint wad) public {
+        if (wad > 0) {
+            TubInterface tub = TubInterface(tub_);
+            tub.draw(cup, wad);
+            tub.sai().transfer(msg.sender, wad);
+        }
+    }
+
+    function handleGovFee(TubInterface tub, uint saiDebtFee, address otc_) internal {
+        bytes32 val;
+        bool ok;
+        (val, ok) = tub.pep().peek();
+        if (ok && val != 0) {
+            uint govAmt = wdiv(saiDebtFee, uint(val));
+            if (otc_ != address(0)) {
+                uint saiGovAmt = OtcInterface(otc_).getPayAmount(tub.sai(), tub.gov(), govAmt);
+                if (tub.sai().allowance(this, otc_) != uint(-1)) {
+                    tub.sai().approve(otc_, uint(-1));
+                }
+                tub.sai().transferFrom(msg.sender, this, saiGovAmt);
+                OtcInterface(otc_).buyAllAmount(tub.gov(), govAmt, tub.sai(), saiGovAmt);
+            } else {
+                tub.gov().transferFrom(msg.sender, this, govAmt);
+            }
+        }
+    }
+
+    function wipe(address tub_, bytes32 cup, uint wad, address otc_) public {
+        if (wad > 0) {
+            TubInterface tub = TubInterface(tub_);
+
+            tub.sai().transferFrom(msg.sender, this, wad);
+            handleGovFee(tub, rmul(wad, rdiv(tub.rap(cup), tub.tab(cup))), otc_);
+
+            if (tub.sai().allowance(this, tub) != uint(-1)) {
+                tub.sai().approve(tub, uint(-1));
+            }
+            if (tub.gov().allowance(this, tub) != uint(-1)) {
+                tub.gov().approve(tub, uint(-1));
+            }
+            tub.wipe(cup, wad);
+        }
+    }
+
+    function wipe(address tub_, bytes32 cup, uint wad) public {
+        wipe(tub_, cup, wad, address(0));
+    }
+
+    function free(address tub_, bytes32 cup, uint jam) public {
+        if (jam > 0) {
+            TubInterface tub = TubInterface(tub_);
+            uint ink = rdiv(jam, tub.per());
+            ink = rmul(ink, tub.per()) <= jam ? ink : ink - 1;
+            tub.free(cup, ink);
+            if (tub.skr().allowance(this, tub) != uint(-1)) {
+                tub.skr().approve(tub, uint(-1));
+            }
+            tub.exit(ink);
+            uint freeJam = tub.gem().balanceOf(this); // Withdraw possible previous stuck WETH as well
+            tub.gem().withdraw(freeJam);
+            address(msg.sender).transfer(freeJam);
+        }
+    }
+
+    function lockAndDraw(address tub_, bytes32 cup, uint wad) public payable {
+        lock(tub_, cup);
+        draw(tub_, cup, wad);
+    }
+
+    function lockAndDraw(address tub_, uint wad) public payable returns (bytes32 cup) {
+        cup = open(tub_);
+        lockAndDraw(tub_, cup, wad);
+    }
+
+    function wipeAndFree(address tub_, bytes32 cup, uint jam, uint wad) public payable {
+        wipe(tub_, cup, wad);
+        free(tub_, cup, jam);
+    }
+
+    function wipeAndFree(address tub_, bytes32 cup, uint jam, uint wad, address otc_) public payable {
+        wipe(tub_, cup, wad, otc_);
+        free(tub_, cup, jam);
+    }
+
+    function shut(address tub_, bytes32 cup) public {
+        TubInterface tub = TubInterface(tub_);
+        wipeAndFree(tub_, cup, rmul(tub.ink(cup), tub.per()), tub.tab(cup));
+        tub.shut(cup);
+    }
+
+    function shut(address tub_, bytes32 cup, address otc_) public {
+        TubInterface tub = TubInterface(tub_);
+        wipeAndFree(tub_, cup, rmul(tub.ink(cup), tub.per()), tub.tab(cup), otc_);
+        tub.shut(cup);
+    }
+}
+
+contract ProxyRegistryInterface {
+    function build(address) public returns (address);
+}
+
+contract SaiProxyCreateAndExecute is SaiProxy {
+
+    // Create a DSProxy instance and open a cup
+    function createAndOpen(address registry_, address tub_) public returns (address proxy, bytes32 cup) {
+        proxy = ProxyRegistryInterface(registry_).build(msg.sender);
+        cup = open(tub_);
+        TubInterface(tub_).give(cup, proxy);
+    }
+
+    // Create a DSProxy instance, open a cup, and lock collateral
+    function createOpenAndLock(address registry_, address tub_) public payable returns (address proxy, bytes32 cup) {
+        proxy = ProxyRegistryInterface(registry_).build(msg.sender);
+        cup = open(tub_);
+        lock(tub_, cup);
+        TubInterface(tub_).give(cup, proxy);
+    }
+
+    // Create a DSProxy instance, open a cup, lock collateral, and draw DAI
+    function createOpenLockAndDraw(address registry_, address tub_, uint wad) public payable returns (address proxy, bytes32 cup) {
+        proxy = ProxyRegistryInterface(registry_).build(msg.sender);
+        cup = open(tub_);
+        lockAndDraw(tub_, cup, wad);
+        TubInterface(tub_).give(cup, proxy);
+    }
+}
\ No newline at end of file