BCredit

BCredit is Mercury credit on Ethereum, with 0% borrow, leverage, deleverage, repay, LTV and BLV-backed solvency, events, errors, and JSON ABI for builders.

Overview

BCredit is borrowing and leverage with 0% interest, a small origination fee, and collateral valued at BLV. Capabilities:

  1. Borrowing : Loans against bToken collateral at BLV
  2. Leverage : Multiplied exposure through borrow + buy loops

Borrowing Functions

borrow

Borrow reserves against bToken collateral. The size must be solvable at BLV with the posted collateral; the contract checks solvency on-chain (no market-oracle liquidation).

function borrow(
  BToken _bToken,
  address _user,
  uint256 _collateralAmount,
  uint256 _borrowAmount
) external returns (uint256 fee_)
ParameterTypeDescription
_bTokenBTokenThe bToken collateral
_useraddressUser borrowing
_collateralAmountuint256bTokens to lock as collateral
_borrowAmountuint256Reserves to borrow

Returns:

  • fee_: Origination fee charged

Note: The borrow must be backed by the posted collateral at BLV (solvency is checked in-contract).


repay

Repay borrowed reserves and unlock collateral.

function repay(
  BToken _bToken,
  address _user,
  uint256 _collateralAmount,
  uint256 _repayAmount
) external
ParameterTypeDescription
_bTokenBTokenThe bToken collateral
_useraddressUser repaying
_collateralAmountuint256Collateral to unlock
_repayAmountuint256Debt to repay

Returns: None (reverts on failure)


Leverage Functions

leverage

Create a leveraged position by borrowing and buying more bTokens.

function leverage(
  BToken _bToken,
  address _user,
  uint256 _collateral,
  uint256 _leverageFactor,
  uint256 _limitAmount
) external returns (
  uint256 collateralAdded_,
  uint256 debtAdded_,
  uint256 collateralIn_,
  uint256 reservesIn_
)
ParameterTypeDescription
_bTokenBTokenThe bToken to leverage
_useraddressUser creating position
_collateraluint256Initial bToken collateral
_leverageFactoruint256Target leverage (WAD, e.g., 2e18 = 2x)
_limitAmountuint256Maximum reserves to spend (slippage)

Returns:

  • collateralAdded_: Total collateral after leverage
  • debtAdded_: Debt created
  • collateralIn_: bTokens used as input
  • reservesIn_: Reserves borrowed

deleverage

Reduce leverage by selling collateral to repay debt.

function deleverage(
  BToken _bToken,
  address _user,
  uint256 _collateralToSell,
  uint256 _limitAmount
) external returns (
  uint256 collateralRedeemed_,
  uint256 debtRepaid_,
  uint256 collateralSold_,
  uint256 refund_
)
ParameterTypeDescription
_bTokenBTokenThe leveraged bToken
_useraddressUser deleveraging
_collateralToSelluint256Collateral to sell for debt repayment
_limitAmountuint256Minimum reserves from sale (slippage)

Returns:

  • collateralRedeemed_: bToken collateral returned to the user
  • debtRepaid_: Debt covered by the operation
  • collateralSold_: bToken collateral sold into the curve for debt repayment
  • refund_: Reserve (or bToken) refund after partial fills, if any (see on-chain BCredit)

View Functions

getCreditAccount

User credit (borrow) position: locked collateral in bTokens and outstanding debt in reserve units.

function getCreditAccount(BToken _bToken, address _user)
  external view returns (State.CreditAccount memory)
ParameterTypeDescription
_bTokenBTokenPool to query
_useraddressUser to query

Returns: State.CreditAccount with collateral (locked bToken), debt (outstanding in reserve), plus any other fields in the in-memory struct


Events

event Borrow(BToken bToken, address user, uint256 borrowed, uint256 fee, State.CreditAccount post);
event Repay(BToken bToken, address user, uint256 collateralRedeemed, uint256 debtRepaid, State.CreditAccount post);
event Leverage(BToken bToken, address user, uint256 collateralAdded, uint256 debtAdded, uint256 collateralIn, uint256 reservesIn, State.CreditAccount post);
event Deleverage(BToken bToken, address user, uint256 collateralRedeemed, uint256 debtRepaid, uint256 collateralSold, uint256 refund, State.CreditAccount post);

Errors

ErrorDescription
BCredit_InsufficientCollateralNot enough collateral for borrow
BCredit_RepaidMoreThanDebtRepaying more than owed
BCredit_Leverage_ZeroCollateralLeverage with no collateral
BCredit_Leverage_BorrowAmountTooLowBorrow doesn't meet minimum
BCredit_Deleverage_InvalidCollateralToSellInvalid deleverage amount
BCredit_Deleverage_UndercollateralizedWould leave position undercollateralized

Usage Example

// Borrow 900 reserves against 1000 bTokens at 90% LTV
bToken.approve(address(bcredit), 1000e18);
uint256 fee = bcredit.borrow(
  bToken,
  msg.sender,
  1000e18,  // collateral
  900e18   // borrow amount
);

// Create 2x leverage
bcredit.leverage(
  bToken,
  msg.sender,
  1000e18,  // initial collateral
  2e18,    // 2x leverage
  1100e18   // max reserves to use
);

// Repay and unlock
reserve.approve(address(bcredit), 900e18);
bcredit.repay(
  bToken,
  msg.sender,
  1000e18,  // collateral to unlock
  900e18   // debt to repay
);

ABI

[
  {
    "type": "function",
    "name": "LABEL",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "function",
    "name": "ROUTES",
    "inputs": [],
    "outputs": [
      {
        "name": "routes_",
        "type": "bytes4[]",
        "internalType": "bytes4[]"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "function",
    "name": "VERSION",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "function",
    "name": "borrow",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_amount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_recipient",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "borrowNative",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_amount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_recipient",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "claimCredit",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_users",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "_collaterals",
        "type": "uint128[]",
        "internalType": "uint128[]"
      },
      {
        "name": "_debts",
        "type": "uint128[]",
        "internalType": "uint128[]"
      },
      {
        "name": "_proofs",
        "type": "bytes32[][]",
        "internalType": "bytes32[][]"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "deleverage",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_collateralToSell",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_minSwapReservesOut",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "collateralRedeemed_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "debtRepaid_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "refund_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "getBorrowForCollateral",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_collateral",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "borrowAmount_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "fee_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "getMaxBorrow",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_user",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "maxBorrow_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "leverage",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_totalCollateral",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_collateralIn",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_maxSwapReservesIn",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "debt_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "previewBorrow",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_borrowAmount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "collateral_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "debt_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "fee_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "previewDepositAndBorrow",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_depositAmount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_borrowAmount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "collateral_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "debt_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "fee_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "previewRebalanceCollateral",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_collateral",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_debt",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "unlocked_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "previewRepay",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_recipient",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_reservesIn",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "collateralRedeemed_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "debtRepaid_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "repay",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_reservesIn",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_recipient",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "repayWithNative",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_recipient",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "payable"
  },
  {
    "type": "function",
    "name": "supportsInterface",
    "inputs": [
      {
        "name": "_interfaceId",
        "type": "bytes4",
        "internalType": "bytes4"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "event",
    "name": "Borrow",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "user",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "borrowed",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "fee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "post",
        "type": "tuple",
        "indexed": false,
        "internalType": "struct State.CreditAccount",
        "components": [
          {
            "name": "collateral",
            "type": "uint128",
            "internalType": "uint128"
          },
          {
            "name": "debt",
            "type": "uint128",
            "internalType": "uint128"
          }
        ]
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "CreditClaim",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "users",
        "type": "address[]",
        "indexed": false,
        "internalType": "address[]"
      },
      {
        "name": "collaterals",
        "type": "uint128[]",
        "indexed": false,
        "internalType": "uint128[]"
      },
      {
        "name": "debts",
        "type": "uint128[]",
        "indexed": false,
        "internalType": "uint128[]"
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Deleverage",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "user",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "collateralRedeemed",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "debtRepaid",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "collateralSold",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "refund",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "post",
        "type": "tuple",
        "indexed": false,
        "internalType": "struct State.CreditAccount",
        "components": [
          {
            "name": "collateral",
            "type": "uint128",
            "internalType": "uint128"
          },
          {
            "name": "debt",
            "type": "uint128",
            "internalType": "uint128"
          }
        ]
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Distributed",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "reserve",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "totalAmount",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "protocolFee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "creatorFee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "stakingFee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Leverage",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "user",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "collateralAdded",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "debtAdded",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "collateralIn",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "reservesIn",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "post",
        "type": "tuple",
        "indexed": false,
        "internalType": "struct State.CreditAccount",
        "components": [
          {
            "name": "collateral",
            "type": "uint128",
            "internalType": "uint128"
          },
          {
            "name": "debt",
            "type": "uint128",
            "internalType": "uint128"
          }
        ]
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Repay",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "user",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "collateralRedeemed",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "debtRepaid",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "post",
        "type": "tuple",
        "indexed": false,
        "internalType": "struct State.CreditAccount",
        "components": [
          {
            "name": "collateral",
            "type": "uint128",
            "internalType": "uint128"
          },
          {
            "name": "debt",
            "type": "uint128",
            "internalType": "uint128"
          }
        ]
      }
    ],
    "anonymous": false
  },
  {
    "type": "error",
    "name": "BCredit_AlreadyClaimed",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_CannotRepayContract",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_Deleverage_InvalidCollateralToSell",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_Deleverage_Undercollateralized",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_InsufficientCollateral",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_InvalidClaim",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_InvalidClaimLength",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_InvalidProof",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_Leverage_BorrowAmountTooLow",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_Leverage_InvalidStakedAmount",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_Leverage_ZeroCollateral",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_NoClaimMerkleRoot",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_RebalanceCollateral_Undercollateralized",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_RepaidMoreThanDebt",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_SystemClaim_Undercollateralized",
    "inputs": []
  },
  {
    "type": "error",
    "name": "BCredit_UserClaim_Undercollateralized",
    "inputs": []
  },
  {
    "type": "error",
    "name": "CollateralLib_InsufficientStake",
    "inputs": []
  },
  {
    "type": "error",
    "name": "Component_NotPermitted",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_Insolvent",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_InsufficientSettledReserves",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_InvalidCirculatingSupply",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_Paused",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_Reentrant",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_ReserveAccountingMismatch",
    "inputs": []
  },
  {
    "type": "error",
    "name": "NativeLib_AmountMismatch",
    "inputs": []
  },
  {
    "type": "error",
    "name": "NativeLib_NotWrapped",
    "inputs": []
  }
]