Baker DAO
Baker DAO
  • documentation
    • Introduction
    • $BREAD Rises
  • What makes BakerDAO Unique
  • Pre-Deposit Vaults and Whitelists
  • Mechanics
    • Baking and Burning
    • Loans
    • Looping
    • Borrowing vs Looping
    • Interest Fees
    • Staking
  • Contract Addresses
  • The Bakery
    • BreadGT
    • Pooled Baking
    • BreadBox
    • Auto TWAP
    • iBREAD
    • GameFi
  • Security
  • User Guide
    • Using the Bake/Burn Page
    • Borrowing with $BREAD Collateral
    • How to use Looping
    • Repaying Loans
  • Links
    • Website
    • Twitter/X
  • Telegram
  • Legal
    • Terms and Conditions
    • Privacy Policy
Powered by GitBook
On this page
  1. Mechanics

Borrowing vs Looping

1-click looping is effectively a "flash loan" mechanism to borrowing all the $BERA needed to establish the position up-front. Additionally it benefits from discounted baking fees. If the fees are the exact same (i.e. bake fee = 2.69% AND looping fee = 2.69%), then the outcome is the same (within a small expected tolerance related to order of operations).

To clarify: calling 1-click loop with 10K BERA is effectively the same thing as having 10K $BERA in your wallet, baking $BREAD with it, and borrowing at 99% LTV against it. Except 1-click loop lets you do it without having any $BERA in your wallet, and for a discounted bake fee!

This is a mathematical property and invariant that is enforced in the code. =lease see the Solidity test written below for an example:

Test comparing looping vs normal borrow:

  • bakeFee and leverageFee are both set to 2.69%

  • 10K $BERA for 365 days


    function test_LoopVsBorrow() public {
        vm.startPrank(bread.owner());
        bread.setLeverageFee(269);
        bread.setBakeFee(269);
        vm.stopPrank();

        uint256 amountToLoop = 10_000 ether;
        uint256 daysToLeverage = 365;

        vm.deal(user4, amountToLoop + 1 ether);
        vm.startPrank(user4);
        {
        uint256 breadLastPriceBefore = bread.lastPrice();
        uint256 beraBalanceBefore = user4.balance;
        console.log("Bread price before: ", breadLastPriceBefore);
        console.log("Bera balance before: ", beraBalanceBefore);
        console.log("Bera balance before: ", bread.balanceOf(user4));
        console.log("Bread totalSupply before:", bread.totalSupply());

        uint256 snapshot = vm.snapshotState();
        uint256 balanceAfterLoop;
        uint256 breadPriceAfterLoop;
        uint256 collateralAfterLoop;
        uint256 borrowedAfterLoop;
        uint256 treasuryBalanceAfterLoop;
        {
            console.log("---testing loop---");
            bread.loop{value: amountToLoop}(amountToLoop, daysToLeverage);

            (uint256 collateral, uint256 borrowed, , ,) = bread.activeLoans(user4);
            balanceAfterLoop = user4.balance;
            breadPriceAfterLoop = bread.prevPrice();
            collateralAfterLoop = collateral;
            borrowedAfterLoop = borrowed;
            treasuryBalanceAfterLoop = address(breadTreasury).balance;
            console.log("Balance after: ", balanceAfterLoop);
            console.log("Collateral after: ", collateralAfterLoop);
            console.log("Borrowed after: ", borrowedAfterLoop);
            console.log("Bread balance after: ", address(bread).balance);
            console.log("Treasury balance after: ", treasuryBalanceAfterLoop);
            console.log("Bread price after: ", breadPriceAfterLoop);
            console.log("Bread totalSupply after:", bread.totalSupply());
        }

        vm.revertToState(snapshot);
        assertEq(breadLastPriceBefore, bread.lastPrice(), "Bread price should be the same after revert");
        assertEq(beraBalanceBefore, user4.balance, "Bera balance should be the same after revert");
        {
            console.log("---testing max borrow after minting BREAD---");
            bread.bake{value: amountToLoop}(user4);
            console.log("Bread balance after mint: ", bread.balanceOf(user4));
            uint256 borrowBasedOnLoopInput = amountToLoop - amountToLoop * bread.leverageFeeBps() / bread.BPS_DENOMINATOR();
            uint256 borrowBasedOnCurrentBread = bread.BREADtoBERAFloor(bread.balanceOf(user4));
            uint256 collateralSaved = (borrokwBasedOnCurrentBread - borrowBasedOnLoopInput) * bread.BPS_DENOMINATOR() / bread.COLLATERAL_RATIO();
            console.log("Borrow to input based on function loop: ", borrowBasedOnLoopInput);
            console.log("Borrow to input based on calc: ", bread.BREADtoBERAFloor(bread.balanceOf(user4)));
            console.log("Collateral saved from calculation difference: ", collateralSaved);
            bread.borrow(borrowBasedOnLoopInput, daysToLeverage); //use the same input as in loop calcs (slightly less due to old bread price)

            (uint256 collateral, uint256 borrowed, , ,) = bread.activeLoans(user4);
            console.log("Balance after: ", user4.balance);
            console.log("Collateral after: ", collateral);
            console.log("Borrowed after: ", borrowed);
            console.log("Bread balance after: ", address(bread).balance);
            console.log("Treasury balance after: ", address(breadTreasury).balance);
            console.log("Bread price after: ", bread.lastPrice());
            console.log("Bread totalSupply after:", bread.totalSupply());
            assertApproxEqAbs(user4.balance, balanceAfterLoop, 1, "Bera balance after borrow should be the same as after loop");
            assertApproxEqAbs(borrowed, borrowedAfterLoop, 1, "Borrowed after borrow should be the same as after loop");
            assertApproxEqAbs(bread.prevPrice(), breadPriceAfterLoop, 1, "Bread price after borrow should be the same as after loop");
            assertApproxEqAbs(collateral, collateralAfterLoop, borrowBasedOnCurrentBread-borrowBasedOnLoopInput, "Collateral after borrow should be same as after loop (ex collateral saved)");
        }
        }
    }
PreviousLoopingNextInterest Fees

Last updated 2 months ago