Cover Image for Blur Blend合约分析
Milo J
Milo J
·

Blur Blend合约分析

地址

  • 审计报告:

https://drive.google.com/file/d/13rmzXIdy138gxPwiGNH8kk-yob4Bjzll/view

名词

贷款:lien

清算:seize

续借:refinance

拍卖:auction

重点

  1. 固定利率,无期限
  1. offer数据和lien数据均不上链,只通过mapping映射lienId和lien的hash
  1. offer只有lender签名,无服务器签名
  1. lender和borrower均可进行refinance,lender refinance时,新的offer利率要比当前并且auctionDuration一样;borrower refinance时,如果新的offer借款不足则要补齐差价
  1. 在auction中任何lender都可以做refinance,利率随着拍卖进行时间变化;任何人可以上链撮合一个新的auction和offer,利率随着拍卖进行时间变化;
  1. 一个offer的amount如果没有被吃完,可以被吃多次,如10个eth,一个borrower借4 eth,另一个借6 eth。

借贷接口

  • borrower执行借贷
function borrow(
        LoanOffer calldata offer,
        bytes calldata signature,
        uint256 loanAmount,
        uint256 collateralTokenId
    )

				/* Lock collateral token. */
        offer.collection.safeTransferFrom(
            msg.sender,
            address(this),
            collateralTokenId
        );

        /* Transfer loan to borrower. */
        pool.transferFrom(offer.lender, msg.sender, loanAmount);
  • borrower还贷
function repay(
        Lien calldata lien,
        uint256 lienId
    )

				/* Repay loan to lender. */
        pool.transferFrom(msg.sender, lien.lender, debt);

  • lender发起auction
function startAuction(
        Lien calldata lien,
        uint256 lienId
    )
				if (msg.sender != lien.lender) {
            revert Unauthorized();
        }

				仅变更lien中的startAuction,重新计算hash

  • lender获取逾期的NFT
function seize(LienPointer[] calldata lienPointers) 

                /* Seize collateral to lender. */
                lien.collection.safeTransferFrom(
                    address(this),
                    lien.lender,
                    lien.tokenId
                );

  • lender做refinance
function refinance(
        Lien calldata lien,
        uint256 lienId,
        LoanOffer calldata offer,
        bytes calldata signature
    )

				if (msg.sender != lien.lender) {
            revert Unauthorized();
        }

			/* Interest rate must be at least as good as current. */
        if (
            offer.rate > lien.rate ||
            offer.auctionDuration != lien.auctionDuration
        ) {
            revert InvalidRefinance();
        }

        /* Repay initial loan. */
        pool.transferFrom(offer.lender, lien.lender, debt);

  • borrower做refinance
function borrowerRefinance(
        Lien calldata lien,
        uint256 lienId,
        uint256 loanAmount,
        LoanOffer calldata offer,
        bytes calldata signature
    ) 

        if (msg.sender != lien.borrower) {
            revert Unauthorized();
        }

  • 任何lender对auction进行refinance
function refinanceAuction(
        Lien calldata lien,
        uint256 lienId,
        uint256 rate
    ) 

        /* Rate must be below current rate limit. */
        uint256 rateLimit = CalculationHelpers.calcRefinancingAuctionRate(
            lien.auctionStartBlock,
            lien.auctionDuration,
            lien.rate
        );
        if (rate > rateLimit) {
            revert RateTooHigh();
        }

				/* Repay the initial loan. */
        pool.transferFrom(msg.sender, lien.lender, debt);

  • 任何人执行一个offer的refinance
function refinanceAuctionByOther(
        Lien calldata lien,
        uint256 lienId,
        LoanOffer calldata offer,
        bytes calldata signature
    ) external validateLien(lien, lienId) auctionIsActive(lien) {
        /* Rate must be below current rate limit and auction duration must be the same. */
        uint256 rateLimit = CalculationHelpers.calcRefinancingAuctionRate(
            lien.auctionStartBlock,
            lien.auctionDuration,
            lien.rate
        );
        if (
            offer.rate > rateLimit ||
            offer.auctionDuration != lien.auctionDuration
        ) {
            revert InvalidRefinance();
        }

        /* Repay initial loan. */
        pool.transferFrom(offer.lender, lien.lender, debt);

市场接口

  • borrower借钱买
function buyToBorrow(
        LoanOffer calldata offer,
        bytes calldata signature,
        uint256 loanAmount,
        Execution calldata execution
    )

  • 买在途再借
function buyToBorrowLocked(
        Lien calldata lien,
        SellInput calldata sellInput,
        LoanInput calldata loanInput,
        uint256 loanAmount
    )

  • 买在途
function buyLocked(
        Lien calldata lien,
        SellOffer calldata offer,
        bytes calldata signature
    )

  • 卖在途
function takeBid(
        Lien calldata lien,
        uint256 lienId,
        Execution calldata execution
    ) 

        if (
            execution.makerOrder.order.trader == address(this) ||
            msg.sender != lien.borrower
        ) {
            revert Unauthorized();
        }