Blur Blend合约分析
Milo J
Milo J
Blur Blend合约分析
地址
- 审计报告:
https://drive.google.com/file/d/13rmzXIdy138gxPwiGNH8kk-yob4Bjzll/view
- 在途拍卖利率计算公式:https://www.desmos.com/calculator/urasr71dhb
名词
贷款:lien
清算:seize
续借:refinance
拍卖:auction
重点
- 固定利率,无期限
- offer数据和lien数据均不上链,只通过mapping映射lienId和lien的hash
- offer只有lender签名,无服务器签名
- lender和borrower均可进行refinance,lender refinance时,新的offer利率要比当前并且auctionDuration一样;borrower refinance时,如果新的offer借款不足则要补齐差价
- 在auction中任何lender都可以做refinance,利率随着拍卖进行时间变化;任何人可以上链撮合一个新的auction和offer,利率随着拍卖进行时间变化;
- 一个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();
}