Lumin

Website: https://lumin.finance/

Documentation: https://docs.lumin.finance/

Abstract

Lumin is a fixed-rate peer-to-peer lending protocol. Planned to support cross-chain loans, the current state support loans on EVM-compatible chains without cross-chain functionality. The first mainnet chain to deploy Lumin on is planned to be Arbitrum.

Before mainnet, the contracts will be tested on Binance Smartchain Testnet and Arbitrum Goerli. Since BSC is no Layer-2 chain, the Chainlink proxy will not have a sequencer set on BSC.

Users deposit their funds into the Lumin platform, which they can use to offer loans in the form of loan configurations. Borrowers create a loan for a specific loan configuration, moving funds from their deposit to the loan collateral.

Any user can liquidate loans when interest and/or principal payments are past due date, or when the value of the assets put down as collateral is lower than the collateral percentage agreed on upon taking the loan.

Contracts

The platform consists of several contracts, where the delivery at this moment is the deposit and loan aspect of the platform. These contracts can be found under ./src. Lumin and Lumin OG NFTs can be found under ./lumin-token, and are not part of the initial platform release. The Lumin token will be added once the launchpad partner and planning has been announced.

Foundry

The project uses Foundry, and all defaults (project layout, formatting, etc) are used unless specified otherwise in foundry.toml.

Solidity style

Best practices as described on https://docs.soliditylang.org are used, with the following explicit choices / deviations:

All import statements are ES6-style named imports.

Although named imports do lead to large import statements and more cluttered lines at the top of Solidity files, it creates clarity about exactly which classes, structs, enums and global variables are imported and helps with understanding and refactoring the actual contract code, which is the most important part of a Solidity file.

The override keyword is only used when overriding virtual functions.

Our opinion is that override should be used to indicate that a function is currently being reimplemented or shadowed, as a hint to the developer. The fact that an interface function is being implemented does not help the developer, and it may even cause confusion when the same keyword has very distinct meanings.

The override keyword is not mandatory when implementing interface functions since Solidity 0.8.8.

Logic clauses

Each logic clause is explicitly separated by its own brackets, not relying on operator precedence.

Bad example:

if (a + b * c < 10 || c > 20)

Good example:

if (((a + (b * c)) < 10) || (c > 20))

Documentation

NatSpec is used, with the addition of the following custom attributes:

@custom:role when set, the method call can only be executed by the set role.

Example:

@custom:role DEFAULT_ADMIN_ROLE

@custom:event event name, one event per line, that the method can emit.

Example:

custom:error AssetAdded

@custom:error error name, one error per line, that the method can revert with. In case the error contains a numeric value used for finer-granularity error reporting, each numeric value is listed as if it were a separate error (on a new line), followed by a short error detail description.

Examples:

@custom:error NotAuthorized

@custom:error IndexOutOfBounds

@custom:error ValidityCheck(100): value too low

@custom:error ValidityCheck(200): value too high

@custom:safe-call <interface/contract>.method for methods performing calls to safe contracts.

Note that a call stack containing a method marked with @custom:unsafe-call is always unsafe, despite the first method in the call stack being marked safe.

Example:

@custom:safe-call IAssetManager.balanceOf

@custom:unsafe-call <interface/contract>.method for methods performing calls to possibly contracts.

Example:

@custom:unsafe-call IERC20.transfer

Access/AccessManager

The AccessManager manages restricted contract calls. It is the authority contract for all Lumin's contracts.

Traits

The upgradeable contract implements the following traits:

OpenZeppelin

AccessManagerUpgradeable

The contract defines the following roles:

  • LUMIN_ADMIN_ROLE for the Lumin team and DAO to upgrade and (un)pause contracts.
  • ASSET_ADMIN_ROLE the asset admins can add and enable/disable assets, price feeds and price feed proxies.
  • LOAN_MANAGER_ROLE the loan manager can perform a limited set of asset actions (deposit, withdraw, (un)lock)
UUPS Proxy

Until Lumin supports all planned features, including cross-chain lending support, the contracts remain upgradeable for fixes and new features. Disabling upgradeability is a choice to be made by the DAO.

Asset/AssetManager

The AssetManager is responsible for holding the user's deposits, locking funds when funds are currently used as deposits, sending funds when loans are taken, etc. Apart from that, the asset's price feeds are managed in this contract as well.

Currently only ERC20 assets are supported. Every ERC20 asset shall have maximum 18 decimals. It is the responsibility of the asset admin to not add ERC20 assets with more decimals, or to update the Lumin contracts to support arbitrary decimals.

Traits

The upgradeable contract implements the following traits:

OpenZeppelin

AccessManagedUpgradeable

The contract has the following restricted methods:

LUMIN_ADMIN_ROLE

  • pause
  • unpause
  • upgradeToAndCall

ASSET_ADMIN_ROLE

  • addAsset
  • setAssetPriceFeed
  • setPriceFeedProxy
  • updateAssetEnabledStatus
  • updateAssetPriceFeedEnableStatus
  • updatePriceFeedProxyEnableStatus

LOAN_MANAGER_ROLE

  • assetLockUnlock
  • assetTransferOnLoanAction
Pausable

In case of suspicious behavior or the discovery of a bug or hack, the Lumin admins can pause the contract, blocking withdrawals from the platform until the issue has been resolved.

Reentrancy Guard

The Lumin protocol inherently trusts all contracts under direct management by the Lumin team. However, actions like withdrawing funds lead to cross-contract calls to contracts not under management by Lumin. Guarding against reentrancy attacks supports in keeping users' deposits safe.

UUPS Proxy

Until Lumin supports all planned features, including cross-chain lending support, the contracts remain upgradeable for fixes and new features. Disabling upgradeability is a choice to be made by the DAO. Upgrades can be performed by LUMIN_ADMIN_ROLE after the contract has been paused.

Cross-contract interactions

The AssetManager has the following cross-contract interactions:

LoanManager

The LoanManager is granted access to AssetManager by means of LOAN_MANAGER_ROLE.

The LoanManager (un)locks users funds and transfer assets, based on loan actions. For example, when a loan is taken, the borrower's collateral assets will be locked and the lender's lent assets will be sent to the borrower's wallet.

ERC20

Whenever the LoanManager transfers funds, or the user withdraws unlocked assets from the contract, the AssetManager will call safeTransfer or safeTransferFrom on the ERC20 asset.

Since this action can lead to a reentrancy attack, the Reentrancy Guard is used when these external calls are made.

Asset ID

Assets are identified by the keccak256 hash of following tuple: (symbol, collection id). For ERC20 and ERC721 assets, this collection id is always 0. For the to-be-supported ERC1155, the collection id indicates the asset ID within the ERC1155 contract.

The asset contract address is not part of this tuple, as the contract addresses of assets across different chains can vary, even though these assets are the exact same asset from a cross-chain functionality point-of-view.

Loan/LoanManagerDelegator

Since the loan management contracts are very close to the maximum code size allowed by EIP-170, a delegator contract is used. All loan management state is stored in the context of this delegator contract.

Traits

The upgradeable contract implements the following traits:

Lumin

  • LoanManagerBase

OpenZeppelin

LoanManagerBase

This base contract defines the storage layout, used by the delegator and all delegatee contracts.

AccessManagedUpgradeable

The contract has the following restricted methods:

LUMIN_ADMIN_ROLE

  • pause
  • unpause
  • upgradeToAndCall
Pausable

In case of suspicious behavior or the discovery of a bug or hack, the Lumin team can pause the contract, blocking loan actions.

UUPS Proxy

Until Lumin supports all planned features, including cross-chain lending support, the contracts remain upgradeable for fixes and new features. Disabling upgradeability is a choice to be made by the DAO.

Reentrancy Guard

The Lumin protocol inherently trusts all contracts under direct management by the Lumin team. However, actions like taking loans lead to cross-contract calls to contracts not under management by Lumin. Guarding against reentrancy attacks supports in keeping users' deposits safe.

Cross-contract interactions

The delegator contract itself executes _delegatecall on LoanConfigManager and LoanManager. All other cross-contract calls are executed by the delegatee contracts. These calls are documented in the delegatee contracts.

Loan/LoanConfigManager

The LoanConfigManager is responsible for the loan configurations created by lenders. This contract is used as delegatee contract, called by LoanManagerDelegator. All storage used by LoanConfigManager and LoanManager stored in the context of LoanManagerDelegator.

Traits

This delegatee contract implements the following traits:

Lumin

  • LoanManagerBase

Cross-contract interactions

The LoanConfigManager has the following cross-contract interactions:

LoanManagerBase

This base contract defines the storage layout, used by the delegator and all delegatee contracts.

AssetManager
  • Request user's asset deposits using depositOf.
  • Request asset's price feeds using getAsset.

The AssetManager is a trusted Lumin contract that can only be set by the Lumin team. The AssetManager does not call external contracts, so the use of this external contract does not impose a risk for reentrancy attacks.

Loan Configuration

Lenders offer loans in the form of loan configuration. Each user is allowed up to 10 loan configurations per asset ID per chain.

A loan configuration has the following attributes:

  • lender: address of loan config creator and initial lender for the loan
  • enabled: true when the loan configuration is currently active, false otherwise. Loans cannot be taken on disabled configurations
  • totalLoanAmount: total amount currently being lent and not paid back to the lender of all loans using this loan configuration. Note that NFTs not owned by lender lead to not deducing total upon paying back the loan. The rationale for this is that the lent asset is not put back into the lender's deposit upon payback.
  • minLoanAmount: minimum amount that can be borrowed per loan
  • maxLoanAmount: maximum amount that can be borrowed per loan
  • maxTotalLoanAmount: maximum value of total; loans can only be taken for this loan configuration as long as total does not exceed maxTotal
  • assetId: asset ID to lend
  • liquidationType: not yet implemented
  • termPaymentType: whether the borrower shall pay a linear share of the interest, or interest and principal, each term
  • acceptedPriceFeeds: bit field indicating which price feeds are allowed to be used to determine the value of the loan
  • interestPromille: interest percentage * 10 (5.6% = 56 promille, 11% = 110 promille)
  • terms: loan duration expressed in terms (see TERM_DURATION)
  • collateralPercentageMinus100: the minimum collateral percentage which the borrower has to supply, in order to prevent liquidation. The value is stored after subtracting 100, as no loan should have less than 100% collateral value. The maximum collateral percentage is therefore type(uint8).max + 100 = 356.
  • safetyBufferPercentage: the minimum additional collateral percentage which the borrower has to supply upon taking a loan and changing the collateral. This percentage prevents liquidations based on small price changes after taking a loan.
  • acceptSignedTerms: not yet implemented

Accepted Asset Configuration

Each loan configuration has a configuration for accepted assets. This is a list of all assets accepted for collateralization and interest payment for the loan, as well as the allowed price feeds to use for value calculation. The lender defines this list, the borrower chooses exactly one price feed to use for the duration of this loan, for each asset.

An example configuration:

assetId[0] = 0x1111111111111111111111111111111111111111;
assetId[1] = 0x2222222222222222222222222222222222222222;
assetId[2] = 0x3333333333333333333333333333333333333333;
assetId[3] = 0x4444444444444444444444444444444444444444;

// Allow asset[0], asset[1] and asset[3] to be used for interest payments
useInterest[0] = true;
useInterest[1] = true;
useInterest[2] = false;
useInterest[3] = true;

// Allow asset[0] and asset[1] to be used as collateral
useCollateral[0] = true;
useCollateral[1] = true;
useCollateral[2] = false;
useCollateral[3] = false;

// Allow price feed index[3] for asset[0], asset[1] and asset[3]
// Allow price feed index[5] for asset[1], asset[2] and asset[3]
priceFeedIndices[0] =  8; // bitfield 0b00001000
priceFeedIndices[1] = 40; // bitfield 0b00101000
priceFeedIndices[2] = 32; // bitfield 0b00100000
priceFeedIndices[3] = 40; // bitfield 0b00101000

Loan/LoanManager

The LoanManager delegatee contract creates loans, allows liquidations, paying back loans and interest, and changing collateral.

The contract is called by LoanManagerDelegator.

Traits

The upgradeable contract implements the following traits:

Lumin

  • LoanManagerBase

Cross-contract interactions

The LoanManager has the following cross-contract interactions:

LoanManagerBase

This base contract defines the storage layout, used by the delegator and all delegatee contracts.

AssetManager
  • (Un)lock user's deposits using assetLockUnlock.
  • Transfers user's deposits using assetTransferOnLoanAction. This can be an internal transfer (e.g. paying interest) or an external transfer (taking a loan, thereby withdrawing the borrowed assets to the user's wallet).
  • Get asset's price feed proxies using getPriceFeedProxyAddress.
  • Get asset's price feeds using getAsset.
PriceFeedProxy
  • Get asset's dollar value using getDollarPrice.

Price Feed

Asset values are read from price feeds using price feed proxy. An example of a price feed proxy is a Chainlink proxy, or a DIA proxy. These proxies read the value of an asset from e.g. Chainlink's or DIA's smart contracts, and returns the Dollar value of one unit of asset (e.g. 1 ETH, 1 BTC, 1 USDT).

Each network can have up to 8 different price feed proxies. All proxies and the price feeds for each asset for that proxy, are matched by their index.

For example:

  • priceFeedProxy[3] = Chainlink

  • priceFeedProxy[5] = DIA

  • BTC.priceFeed[3] = 0x1234 (Chainlink)

  • ETH.priceFeed[3] = 0x5678 (Chainlink)

  • ETH.priceFeed[5] = 0x90AB (DIA)

In this example, ETH supports Chainlink and DIA price feeds, and BTC only supports the Chainlink price feed.

Loan configurations contain a list of accepted price feeds using a bit mask. For example, 00000101 indicates that priceFeed[0] and priceFeed[2] are accepted.

When taking a loan, the borrower selects exactly one price feed for each asset accepted by the lender. The selected price feed cannot be changed during the loan; the values used in all calculations for paying interest, liquidating, etc. are based on the price feeds chosen by the borrower, where the borrower can choose from those price feeds allowed by the lender in the loan configuration.

Loan/LoaNFT

A LoaNFT signifies the ownership of a loan. For each loan, a total of 10 LoaNFTs are minted. When the loan has been closed, the LoaNFTs are burned. Every interest and principal payment done to a loan is shared over the LoaNFT owners, where each owner receives their respective share of the payment.

When a loan is liquidated, LoaNFT owners receive their share of the collateral according to the same share split.

Traits

The upgradeable contract implements the following traits:

OpenZeppelin

AccessManagedUpgradeable

The contract has the following restricted methods:

LOAN_MANAGER_ROLE

  • burn
  • mint
ERC1155Upgradeable

LoaNFTs are ERC1155 tokens, where the token ID corresponds to the loan ID and each token ID exist of 10 tokens (shares).

UUPS Proxy

Until Lumin supports all planned features, including cross-chain lending support, the contracts remain upgradeable for fixes and new features. Disabling upgradeability is a choice to be made by the DAO.

Cross-contract interactions

The LoaNFT has the following cross-contract interactions:

LoanManager
  • LoanManager mints 10 LoaNFTs to the lender upon creating a loan.
  • LoanManager burns 10 LoaNFTs upon closing a loan.
  • LoanManager reads current LoanNFT ownership and amount of shares for each owner.

Example contract flow

After deploying and configuring the contracts, the admin adds the following assets (note that this is pseudocode):

assetETH  = AssetManager.addAsset(ethTokenAddress, "ETH", 0)
assetBTC  = AssetManager.addAsset(btcTokenAddress, "BTC", 0)
assetUSDC = AssetManager.addAsset(usdcTokenAddress, "USDC", 0)

For all of these assets, there is both a Chainlink and DIA price feed proxy:

priceFeedProxy[0] = AssetManager.setPriceFeedProxy(0, chainlink);
priceFeedProxy[1] = AssetManager.setPriceFeedProxy(1, dia);

Alice deposits assets into her account:

AssetManager.assetDepositWithdraw(assetETH, AssetActionType.Deposit, 1)
AssetManager.assetDepositWithdraw(assetUSDC, AssetActionType.Deposit, 1000)

Bob deposits assets as well:

AssetManager.assetDepositWithdraw(assetETH, AssetActionType.Deposit, 10)
AssetManager.assetDepositWithdraw(assetBTC, AssetActionType.Deposit, 2)

Alice wants to lend out her USDC, with a minimum loan size of 100 USDC, maximum of 250 USDC, and does not want to lend out more than 500 USDC at any point in time with this configuration. She only accepts ETH as collateral, but she is fine receiving interest payments in USDC and ETH. She does not want BTC to be used as collateral or for interest payments. She is fine using either DIA or Chainlink for the loans taken from her configuration.

configId_1  = LoanManager.createConfig:
  - asset                  : assetUSDC
  - minLoanAmount          : 100
  - maxLoanAmount          : 250
  - maxTotalLoanAmount     : 500
  - terms                  : 4 (120 days)
  - interestPromille       : 120 (12%)

  - assets:
    - ETH                  : interest, collateral
    - USDC                 : interest

This leads to the following contract state:

LoanConfigManager.loanConfig[1]

  - lender                 : Alice
  - asset                  : assetUSDC
  - minLoanAmount          : 100
  - maxLoanAmount          : 250
  - maxTotalLoanAmount     : 500
  - terms                  : 4 (30 days)
  - interestPromille       : 120 (12%)
  - assetUsage             :
    - assetId[0]               : assetETH
    - assetId[1]               : assetUSDC

    - priceFeedIndices[0]      : 0b00000011
    - priceFeedIndices[1]      : 0b00000011

The following container stores the loan configuration IDs created for a specific asset, per user. This is to quickly search all active loans for each user, and to make sure that people do not create too many loans IDs and bloat the contract data.

LoanConfigManager.userConfigIds[Alice]

  [assetETH]: [1]

Bob wants to borrow 150 USDC from Alice, he creates a loan using Alice's configuration (ID 1). As collateral he puts down 0.2 ETH. For ETH valuation he wants to use DIA, but for USDC he prefers Chainlink.

loan_1 = LoanManager.createLoan:
  - configId                : 1
  - loanAmount              : 150
  - priceFeedIndex          : 0 (Chainlink)

  - loan assets:
    - [0 (ETH)]
      - amount              : 0.2
      - priceFeedIndex      : 1 (DIA)
    - [1 (USDC)]
      - amount              : 0
      - priceFeedIndex      : 0 (Chainlink)

This leads to the following contract state:

LoanManager.loans[1]

  - borrower                : Bob
  - loanStart               : <day 0>
  - loan
    - configId              : 1
    - loanAmount            : 150
    - pendingPrincipalAmount: 150
    - pendingInterestAmount : 18 // 12% of 150
    - priceFeedIndex        : 0
  - collateralAssets
    - amount[0]             : 0.2
    - amount[1]             : 0

    - priceFeedIndex[0]     : 1
    - priceFeedIndex[1]     : 0

LoaNFT._owners[1]

  - address                 : Bob

Note that the borrower can choose a different price feed for an asset used for payments, than that used for the loan valuation.

Upon creation of the loan, Bob's 0.2 ETH remain in his deposit, but become locked. The borrowed 150 USDC is transferred to Bob's wallet, and leave the Lumin platform immediately.

If termPaymentType is Interest or InterestAndPrincipal, Bob needs to pay his first instalment before the first term of 30 days are over. Instalments are linear payments over the interest (and optionally the principal) due, but they can be paid in advance. Bob decides to already pay half of the due interest. Remember that Alice allows interest payments with ETH and USDC.

12% of $150 = $18 total interest. Bob wants to pay half, so he puts down 0.005 ETH (assume this is 9 USDC).

LoanManager.pay:
  - loanId                  : 1
  - interest assets:
    - [0 (ETH)]             : 0.005
    - [1 (BTC)]             : 0
  - principal               : 0

This leads to the following updated contract state: LoanManager.loans[1]

  - borrower                : Bob
  - loanStart               : <day 0>
  - loan
    - configId              : 1
    - loanAmount            : 150
    - pendingPrincipalAmount: 150
    - pendingInterestAmount : 9
    - priceFeedIndex        : 0

Note that the price feeds cannot be set anymore; Bob decided on the price feeds to use when he took the loan.

Bob's loan has a duration of 4 terms (120 days), which means that his 50% payment of the interest will cover the loan until 60 days after loanStart, but they need topping up in time. Paying interest can be done by any user on the platform, provided that they pay with the assets and price feeds selected by Bob when creating the loan.

Note that the percentage of principal paid is not allowed to be higher than the percentage of interest paid. The possible term payment options are as follows: None, Interest, InterestAndPrincipal.

  • None: interest and principal can be paid at any time, maximum by the end of the loan duration.
  • Interest: interest and principal can be paid at any time, where the interest payment needs to be paid at least linearly in 30-day installments. Payments can be done upfront.
  • InterestAndPrincipal: interest and principal can be paid at any time, but need to be paid at least linearly in 30-day installments. Payments can be done upfront.

Bob can choose to update his collateral by providing a list of all new collateral amounts. Any surplus will become unlocked deposits, any tokens to be provided as extra collateral will be locked.

For example, reducing collateral:

LoanManager.setCollateral

  - loanId                  : 1
  - collateral assets:
    - [0 (ETH)]             : 0.004
    - [1 (BTC)]             : 0

As long as the Dollar value of the collateral is at least the collateral + safety buffer percentage as required by Alice in the loan configuration, the collateral can be changed.

In case the collateral value is lower than the collateral percentage as configured by Alice, or the total interest paid is not enough according to the linear payment per term, the loan can be liquidated:

LoanManager.liquidate(1)

This splits all locked collateral as follows:

  • 25% to the liquidator's free deposit
  • 50% to the LoanManager contract's free deposit, to be split between platform fees and staker rewards
  • 25% to the loan's owners, where ownership is determined by the corresponding LoaNFT ownership shares. Each loan has a total of 10 corresponding LoaNFT shares, each signifying a 10% ownership of the loan.

After the collateral is split, the loan and corresponding LoaNFTs are deleted.

Note that the lenders are the persons holding the corresponding LoaNFTs at the time of a loan action (interest, loan repayment, liquidation).

The order of loan payments is as follows:

  • platform fee payment (automatically deducted upon creating a loan)
  • interest payment and / or principal repayment

Only after a successful platform loan payment or liquidation, the loan is fully removed.

Platform fees are 10% of the total interest to be paid over a loan, and are automatically paid upon taking a loan. This means that the borrower receives the full borrowed value, minus 10% of the total interest due, upon taking a loan.

For example:

loanConfig[123]:
  interestPromille          : 30 // 3%
  minLoanAmount             : 1000
  ...

loan[1000]:
  configId                  : 123
  loanAmount                : 1000

The total interest due is 3% over 1000 = 30. The platform fees are 10% = 3, so the borrower receives 1000 - 3 = 997 upon taking the loan.

Contents

LuminAccessManager

Git Source

Inherits: AccessManagerUpgradeable, UUPSUpgradeable

Author: bull.haus

Central access manager for all restricted Lumin contract calls.

Functions

constructor

constructor();

initialize

Upgradeable contract initializer.

function initialize(address initialAdmin) external initializer;

Parameters

NameTypeDescription
initialAdminaddressInitial admin of this contract. Can differ from the deployer.

_authorizeUpgrade

Validate that the upgrader has the LUMIN_ADMIN_ROLE.

function _authorizeUpgrade(address) internal view override;

LuminRoles

Git Source

Lumin roles, used by AccessManager for all Lumin contracts.

LUMIN_ADMIN_ROLE The lumin admin can pause/unpause and upgrade contracts.

ASSET_ADMIN_ROLE The asset admins can add and enable/disable assets, price feeds and price feed proxies.

LOAN_MANAGER_ROLE Asset actions (deposit, withdraw, (un)lock) are allowed for the LoanManager contract.

enum LuminRoles {
    INVALID_ROLE,
    LUMIN_ADMIN_ROLE,
    ASSET_ADMIN_ROLE,
    LOAN_MANAGER_ROLE
}

Contents

AssetManager

Git Source

Inherits: IAssetManager, AccessManagedUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable, UUPSUpgradeable

Author: bull.haus

Registers all assets supported for P2P loans on Lumin

State Variables

registeredAssets

Set of all Asset IDs registered on the platform.

This list is unique per chain; not all chains support the same assets. Assets are never removed, but support can be disabled / enabled.

EnumerableSet.UintSet private registeredAssets;

assets

Mapping of all Asset configurations on the platform.

This mapping contains all enabled and disabled assets ever supported by the platform on this chain.

mapping(uint256 => Asset) private assets;

deposits

Mapping of all assets (by Asset ID), to mapping of all users' (by address) Deposits.

mapping(uint256 => mapping(address => DepositData)) private deposits;

priceFeedProxies

List of price feed proxy contract addresses and enabled/disabled status.

The indices of this list correspond to the indices of the price feeds for each asset.

EnabledAddress[MAX_PRICE_FEED_PROXIES] private priceFeedProxies;

assetPriceFeeds

Mapping of all price feeds for each asset.

The index in the EnabledAddress array indicates the index used for the PriceFeedProxy. Address(0) indicates a non-configured price feed.

mapping(uint256 => EnabledAddress[MAX_PRICE_FEED_PROXIES]) private assetPriceFeeds;

Functions

assetExists

modifier assetExists(uint256 assetId);

constructor

constructor();

initialize

Upgradeable contract initializer.

function initialize(address initialAdmin) external initializer;

Parameters

NameTypeDescription
initialAdminaddressInitial admin of this contract. Can differ from the deployer.

pause

Pause contract.

function pause() external restricted whenNotPaused;

unpause

Unpause contract.

function unpause() external restricted whenPaused;

addAsset

Add asset to the platform. This allows users to deposit, withdraw and lend with this asset.

assetType is currently an unnamed variable. This shall be changed when other asset types besides ERC20 are supported.

collectionId is currently an unnamed variable. This shall be changed when assets supporting collections (e.g. ERC1155) are supported.

function addAsset(AssetType, address assetAddress, string calldata symbol, uint256) external restricted;

Parameters

NameTypeDescription
<none>AssetType
assetAddressaddresscontract address of added asset
symbolstringasset symbol (e.g. BTC, ETH)
<none>uint256

updateAssetEnabledStatus

Enable / disable asset.

Assets configs can not be deleted; disable assets when not supported anymore.

function updateAssetEnabledStatus(uint256 assetId, bool enabled) external assetExists(assetId) restricted;

Parameters

NameTypeDescription
assetIduint256unique asset identifier
enabledbooltrue to enable asset, false to disable asset

assetDepositWithdraw

Deposit or withdraw asset from user's account

Only AssetActionType.Deposit and AssetActionType.Withdraw are allowed

function assetDepositWithdraw(uint256 assetId, AssetActionType action, uint256 amount) external;

Parameters

NameTypeDescription
assetIduint256asset id to deposit or withdraw
actionAssetActionTypeasset action to perform (AssetActionType.Deposit, AssetActionType.Withdraw)
amountuint256amount to deposit or withdraw

assetTransferOnLoanAction

Transfer assets from one user to another.

Transfers happen for payments (e.g. interest), lending (transferring lent money) and seizing (liquidated loan). Transfers are performed on user's deposits on Lumin, no ERC20 transfers are executed.

function assetTransferOnLoanAction(
    uint256 assetId,
    AssetActionType action,
    address userAddressFrom,
    address userAddressTo,
    uint256 amount
) external restricted;

Parameters

NameTypeDescription
assetIduint256asset id to transfer
actionAssetActionTypeaction to perform
userAddressFromaddressaddress to transfer asset from
userAddressToaddressaddress to transfer asset to
amountuint256to transfer

assetLockUnlock

Lock / unlock asset.

This method is called by the LoanManager

function assetLockUnlock(uint256 assetId, AssetActionType action, address userAddress, uint256 amount)
    external
    restricted;

Parameters

NameTypeDescription
assetIduint256asset id to (un)lock
actionAssetActionTypelock / unlock
userAddressaddressuser address to (un)lock for
amountuint256amount to (un)lock

setPriceFeedProxy

Set price feed proxy address

function setPriceFeedProxy(uint256 index, address priceFeedProxyAddress) external restricted;

Parameters

NameTypeDescription
indexuint256index to store price feed proxy at
priceFeedProxyAddressaddressaddress of price feed proxy. Setting address(0) reverts with ZeroAddress.

updatePriceFeedProxyEnableStatus

Enable / disable price feed proxy by address

Price feed proxy has to be added with addPriceFeedProxy first.

function updatePriceFeedProxyEnableStatus(uint256 index, bool enabled) external restricted;

Parameters

NameTypeDescription
indexuint256price feed proxy index
enabledbooltrue to enable, false to disable price feed proxy

setAssetPriceFeed

Set price feed for asset at given index

function setAssetPriceFeed(uint256 assetId, uint256 priceFeedIndex, address priceFeedAddress)
    external
    assetExists(assetId)
    restricted;

Parameters

NameTypeDescription
assetIduint256asset id to set price feed for
priceFeedIndexuint256index of price feed to set
priceFeedAddressaddressaddress of price feed. Setting address(0) reverts with ZeroAddress.

updateAssetPriceFeedEnableStatus

Enable / disable price feed for asset at given index

function updateAssetPriceFeedEnableStatus(uint256 assetId, uint256 priceFeedIndex, bool enabled)
    external
    assetExists(assetId)
    restricted;

Parameters

NameTypeDescription
assetIduint256asset id to enable/disable price feed for
priceFeedIndexuint256index of price feed to set
enabledbooltrue to enable, false to disable

upgradeToAndCall

UUPS-upgrade contract.

function upgradeToAndCall(address newImplementation, bytes memory data) public payable override restricted whenPaused;

Parameters

NameTypeDescription
newImplementationaddressAddress of newly deployed contract.
databytesInitial setup call data.

getRegisteredAssetIDs

Retrieve all known asset IDs

When asset IDs are unknown, this method can be used to find all known assets. Since the data is read from an EnumerableSet, the asset ID belonging to a certain index may change. This does not matter, as it is the asset ID that is important, not its index.

function getRegisteredAssetIDs() external view returns (uint256[] memory);

Returns

NameTypeDescription
<none>uint256[]list of all known asset IDs

depositOf

Get deposit of asset assetId for user userAddress.

Returns 0 deposit for non-existent assets or users.

function depositOf(uint256 assetId, address userAddress)
    external
    view
    assetExists(assetId)
    returns (DepositData memory userDeposit);

Parameters

NameTypeDescription
assetIduint256id of asset
userAddressaddressuser's address to get deposit for

Returns

NameTypeDescription
userDepositDepositDataDeposit of userAddress for asset assetAddress

balancesOf

Get deposits and balances for user userAddress.

This method is used to quickly retrieve the most important dashboard data by the front-end, with one RPC call.

function balancesOf(address userAddress)
    external
    view
    returns (
        uint256[] memory assetIds,
        DepositData[] memory depositsTotal,
        DepositData[] memory depositsUser,
        uint256[] memory balances
    );

Parameters

NameTypeDescription
userAddressaddressuser's address to get balances for. address(0) for asset totals.

Returns

NameTypeDescription
assetIdsuint256[]Ordered list of asset ids for which balances are returned
depositsTotalDepositData[]Ordered list of total Deposits
depositsUserDepositData[]Ordered list of Deposits of userAddress
balancesuint256[]Ordered list of wallet balances of userAddress. Empty array if userAddress is address(0).

getPriceFeedProxies

Get all price feed proxies

function getPriceFeedProxies() external view returns (IAssetManager.EnabledAddress[MAX_PRICE_FEED_PROXIES] memory);

Returns

NameTypeDescription
<none>IAssetManager.EnabledAddress[MAX_PRICE_FEED_PROXIES]Array of all price feed proxies

getPriceFeedProxyAddress

Get price feed proxy address by index

function getPriceFeedProxyAddress(uint256 index) external view returns (address);

Parameters

NameTypeDescription
indexuint256index to get price feed proxy address from

Returns

NameTypeDescription
<none>addressaddress of price feed proxy at index

getAsset

Retrieve asset information based on its asset ID

function getAsset(uint256 assetId)
    public
    view
    assetExists(assetId)
    returns (Asset memory asset, EnabledAddress[MAX_PRICE_FEED_PROXIES] memory priceFeeds);

Parameters

NameTypeDescription
assetIduint256asset ID to find information for

Returns

NameTypeDescription
assetAssetasset details
priceFeedsEnabledAddress[MAX_PRICE_FEED_PROXIES]configured price feeds for asset

_authorizeUpgrade

Allow upgrades when contract is paused.

Method is necessary for OZ's UUPSUpgradeable contracts.

function _authorizeUpgrade(address) internal pure override;

_assetAction

function _assetAction(uint256 assetId, AssetActionType action, address userAddress, uint256 amount)
    private
    assetExists(assetId)
    nonReentrant
    whenNotPaused;

_depositWithdraw

This method has been optimized for ERC20-only usage. The asset id will need to be re-implemented when other asset types are supported.

function _depositWithdraw(address assetAddress, bool deposit, address sender, uint256 amount) private;

Contents

IAggregatorV3

Git Source

Author: bull.haus

Chainlink price feed interface.

See https://github.com/smartcontractkit/chainlink

Functions

decimals

function decimals() external view returns (uint8);

description

function description() external view returns (string memory);

version

function version() external view returns (uint256);

getRoundData

function getRoundData(uint80 _roundId)
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

latestRoundData

function latestRoundData()
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

IAssetManager

Git Source

Author: bull.haus

Registers all assets supported for P2P loans on Lumin.

Functions

pause

Pause contract.

function pause() external;

unpause

Unpause contract.

function unpause() external;

addAsset

Add asset to the platform. This allows users to deposit, withdraw and lend with this asset.

Only ERC20 assets are currently supported.

function addAsset(AssetType assetType, address assetAddress, string calldata symbol, uint256 collectionId) external;

Parameters

NameTypeDescription
assetTypeAssetTypetype of added asset
assetAddressaddresscontract address of added asset
symbolstringasset symbol (e.g. BTC, ETH)
collectionIduint256id of asset collection. This does not apply to ERC20 assets, and is set to 0 by default

updateAssetEnabledStatus

Enable / disable asset.

Assets configs can not be deleted; disable assets when not supported anymore.

function updateAssetEnabledStatus(uint256 assetId, bool enabled) external;

Parameters

NameTypeDescription
assetIduint256unique asset identifier
enabledbooltrue to enable asset, false to disable asset

assetDepositWithdraw

Deposit or withdraw asset from user's account

Only AssetActionType.Deposit and AssetActionType.Withdraw are allowed

function assetDepositWithdraw(uint256 assetId, AssetActionType action, uint256 amount) external;

Parameters

NameTypeDescription
assetIduint256asset id to deposit or withdraw
actionAssetActionTypeasset action to perform (AssetActionType.Deposit, AssetActionType.Withdraw)
amountuint256amount to deposit or withdraw

assetTransferOnLoanAction

Transfer assets from one user to another.

Transfers happen for payments (e.g. interest), lending (transferring lent money) and seizing (liquidated loan). Transfers are performed on user's deposits on Lumin, no ERC20 transfers are executed.

function assetTransferOnLoanAction(
    uint256 assetId,
    AssetActionType action,
    address userAddressFrom,
    address userAddressTo,
    uint256 amount
) external;

Parameters

NameTypeDescription
assetIduint256asset id to transfer
actionAssetActionTypeaction to perform
userAddressFromaddressaddress to transfer asset from
userAddressToaddressaddress to transfer asset to
amountuint256to transfer

assetLockUnlock

Lock / unlock asset.

This method is called by the LoanManager

function assetLockUnlock(uint256 assetId, AssetActionType action, address userAddress, uint256 amount) external;

Parameters

NameTypeDescription
assetIduint256asset id to (un)lock
actionAssetActionTypelock / unlock
userAddressaddressuser address to (un)lock for
amountuint256amount to (un)lock

setPriceFeedProxy

Set price feed proxy address

function setPriceFeedProxy(uint256 index, address priceFeedProxyAddress) external;

Parameters

NameTypeDescription
indexuint256index to store price feed proxy at
priceFeedProxyAddressaddressaddress of price feed proxy. Setting address(0) reverts with ZeroAddress.

updatePriceFeedProxyEnableStatus

Enable / disable price feed proxy by address

Price feed proxy has to be added with addPriceFeedProxy first.

function updatePriceFeedProxyEnableStatus(uint256 index, bool enabled) external;

Parameters

NameTypeDescription
indexuint256price feed proxy index
enabledbooltrue to enable, false to disable price feed proxy

setAssetPriceFeed

Set price feed for asset at given index

function setAssetPriceFeed(uint256 assetId, uint256 priceFeedIndex, address priceFeedAddress) external;

Parameters

NameTypeDescription
assetIduint256asset id to set price feed for
priceFeedIndexuint256index of price feed to set
priceFeedAddressaddressaddress of price feed. Setting address(0) reverts with ZeroAddress.

updateAssetPriceFeedEnableStatus

Enable / disable price feed for asset at given index

function updateAssetPriceFeedEnableStatus(uint256 assetId, uint256 priceFeedIndex, bool enabled) external;

Parameters

NameTypeDescription
assetIduint256asset id to enable/disable price feed for
priceFeedIndexuint256index of price feed to set
enabledbooltrue to enable, false to disable

getRegisteredAssetIDs

Retrieve all known asset IDs

When asset IDs are unknown, this method can be used to find all known assets. Since the data is read from an EnumerableSet, the asset ID belonging to a certain index may change. This does not matter, as it is the asset ID that is important, not its index.

Assets can be enabled and disabled but never deleted. A returned known asset ID does not imply that this asset is currently enabled.

function getRegisteredAssetIDs() external view returns (uint256[] memory);

Returns

NameTypeDescription
<none>uint256[]list of all known asset IDs

depositOf

Get deposit of asset assetId for user userAddress.

Returns 0 deposit for non-existent assets or users.

function depositOf(uint256 assetId, address userAddress) external view returns (DepositData memory userDeposit);

Parameters

NameTypeDescription
assetIduint256id of asset
userAddressaddressuser's address to get deposit for

Returns

NameTypeDescription
userDepositDepositDataDeposit of userAddress for asset assetAddress

balancesOf

Get deposits and balances for user userAddress.

This method is used to quickly retrieve the most important dashboard data by the front-end, with one RPC call.

function balancesOf(address userAddress)
    external
    view
    returns (
        uint256[] memory assetIds,
        DepositData[] memory depositsTotal,
        DepositData[] memory depositsUser,
        uint256[] memory balances
    );

Parameters

NameTypeDescription
userAddressaddressuser's address to get balances for. address(0) for asset totals.

Returns

NameTypeDescription
assetIdsuint256[]Ordered list of asset ids for which balances are returned
depositsTotalDepositData[]Ordered list of total Deposits
depositsUserDepositData[]Ordered list of Deposits of userAddress
balancesuint256[]Ordered list of wallet balances of userAddress. Empty array if userAddress is address(0).

getPriceFeedProxies

Get all price feed proxies

function getPriceFeedProxies() external view returns (EnabledAddress[MAX_PRICE_FEED_PROXIES] memory);

Returns

NameTypeDescription
<none>EnabledAddress[MAX_PRICE_FEED_PROXIES]Array of all price feed proxies

getPriceFeedProxyAddress

Get price feed proxy address by index

function getPriceFeedProxyAddress(uint256 index) external view returns (address);

Parameters

NameTypeDescription
indexuint256index to get price feed proxy address from

Returns

NameTypeDescription
<none>addressaddress of price feed proxy at index

getAsset

Retrieve asset information based on its asset ID

function getAsset(uint256 assetId)
    external
    view
    returns (Asset memory asset, EnabledAddress[MAX_PRICE_FEED_PROXIES] memory priceFeeds);

Parameters

NameTypeDescription
assetIduint256asset ID to find information for

Returns

NameTypeDescription
assetAssetasset details
priceFeedsEnabledAddress[MAX_PRICE_FEED_PROXIES]configured price feeds for asset

Events

AssetAction

Emitted when an asset is transferred or (un)locked on the platform.

event AssetAction(uint256 indexed assetId, AssetActionType indexed action, address indexed userAddress, uint256 amount);

AssetAdded

Emitted when asset is been added.

event AssetAdded(
    uint256 indexed assetId, address indexed assetAddress, uint256 indexed collectionId, AssetType assetType
);

AssetEnabledStatusUpdated

Indicates that an asset has been enabled / disabled.

Only assets that have been added to the platform can be enabled.

event AssetEnabledStatusUpdated(uint256 indexed assetId, bool indexed enabled);

PriceFeedEnabledStatusUpdated

Emitted when a price feed status has been updated

event PriceFeedEnabledStatusUpdated(uint256 assetId, uint256 priceFeedIndex, bool enabled);

PriceFeedSet

Emitted when a price feed has been set for an asset

event PriceFeedSet(uint256 assetId, uint256 priceFeedIndex, address priceFeedAddress);

PriceFeedProxySet

Emitted when a price feed proxy has been added

event PriceFeedProxySet(address indexed priceFeedProxyAddress, uint256 indexed index);

PriceFeedProxyEnabledStatus

Emitted when a price feed proxy status has been updated

event PriceFeedProxyEnabledStatus(uint256 indexed index, bool indexed enabled);

Errors

AssetAlreadyRegistered

Registering already existing assets revert with AssetAlreadyRegistered.

error AssetAlreadyRegistered();

AssetNotEnabled

Using assets currently not enabled revert with AssetNotEnabled,

error AssetNotEnabled();

AssetNotFound

Getting non-existent assets reverts with AssetNotFound,

error AssetNotFound();

InsufficientFunds

Transferring more assets than currently in free deposits reverts with InsufficientFunds.

Transfers are deposits, payments, taking loans, ..

error InsufficientFunds();

InvalidAction

Performing an asset action not supported by the called method revert with InvalidAction.

error InvalidAction();

PriceFeedAlreadySet

Overwriting a previously set price feed reverts with PriceFeedAlreadySet

Changing the contract could result in unwanted issues like liquidations.

error PriceFeedAlreadySet();

PriceFeedNotSet

Actions on price feed proxies that were not configured, revert with PriceFeedNotSet.

error PriceFeedNotSet();

PriceFeedProxyDisabled

Actions on disabled price feed proxies, revert with ProxyDisabled

error PriceFeedProxyDisabled();

PriceFeedProxyAlreadySet

Overwriting a previously set price feed proxy reverts with PriceFeedProxyAlreadySet.

Changing the contract could result in unwanted issues like liquidations.

Disable the price feed proxy instead, and add a new one on a different index.

error PriceFeedProxyAlreadySet();

ZeroAddress

Setting a price feed or proxy with zero address reverts with ZeroAddress.

error ZeroAddress();

ZeroAmount

Performing asset actions on "0" amount of tokens reverts with ZeroAmount.

error ZeroAmount();

Structs

DepositData

Tuple containing amount deposited, and total amount locked over all loans.

(Un)locking assets does not change the deposit amount; 0 <= locked <= amount at all times.

depositAmount Total amount of asset deposited into user's account.

lockedAmount Amount of depositAmount that is currently locked as collateral.

struct DepositData {
    uint256 depositAmount;
    uint256 lockedAmount;
}

Asset

Asset configuration.

Assets shall not be deleted to prevent invalid loans, they should be enabled/disabled instead.

assetType Type of asset (e.g. ERC20).

collectionId Collection ID, only used for ERC1155 assets.

data Asset contract address and enabled status. Disabled assets cannot be used in new loans or for deposits.

struct Asset {
    AssetType assetType;
    uint256 collectionId;
    EnabledAddress data;
}

EnabledAddress

Tuple of address and enabled flag

Used by different types

enabled true when the current asset or contract can be used, false otherwise.

addr asset or contract address.

struct EnabledAddress {
    bool enabled;
    address addr;
}

Enums

AssetActionType

Asset action to perform.

The respective values are used for performing asset action methods and emitted events.

NotSupported 0-value used to indicate an invalid action.

Lock Lock user's deposit.

Unlock Unlock user's deposit.

Deposit Deposit asset to user's unlocked deposit.

Withdraw Withdraw asset from user's unlocked deposit.

Lend Lend an asset from lender to borrower.

PayFees Pay platform fees for newly created loan from borrower's deposit.

PayInterest Pay loan interest to lenders.

PayPrincipal Pay principal to lenders.

Seize Seize collateral from borrower on liquidation.

enum AssetActionType {
    NotSupported,
    Lock,
    Unlock,
    Deposit,
    Withdraw,
    Lend,
    PayFees,
    PayInterest,
    PayPrincipal,
    Seize
}

AssetType

Type of asset indicates where to read and how to handle user deposits and collateral.

Disabled has value 0 so that by default all non-configured assets are marked as disabled. ERC1155Fungible are assets within an ERC1155 contract, where amount > 1, and are thus fungible. ERC1155NonFungible are assets within an ERC1155 contract, where amount == 1, and are thus non-fungible.

enum AssetType {
    Disabled,
    ERC20
}

Constants

Git Source

MAX_PRICE_FEED_PROXIES

uint256 constant MAX_PRICE_FEED_PROXIES = 8;

ILoaNFT

Git Source

Inherits: IERC1155

Author: bull.haus

LoaNFT ERC1155 contract. Owners of LoaNFTs are (partial) lenders of loans on Lumin. LoaNFTs are transferrable.

Burning and minting of LoaNFTs is done by the LoanManager contract.

Each loan consists of 10 shares, each indicating 10% ownership of future payments of the loan.

Functions

mint

Mint LoaNFT token to given user address.

Can only be called by LoanManager.

function mint(address to, uint256 tokenId) external;

Parameters

NameTypeDescription
toaddressuser address to mint LoaNFT for
tokenIduint256LoaNFT token identifier, which is the same as the loan id

burn

Burn LoaNFT token.

Can only be called by LoanManager.

function burn(uint256 tokenId) external;

Parameters

NameTypeDescription
tokenIduint256LoaNFT token identifier, which is the same as the loan id

sharesOf

Get the owners and respective loan shares of each loan owner.

function sharesOf(uint256 tokenId) external view returns (LoanShare[] memory shares);

Parameters

NameTypeDescription
tokenIduint256LoaNFT token identifier for which to get loan ownership shares

Returns

NameTypeDescription
sharesLoanShare[]List of owners and respective loan share of each loan owner

Structs

LoanShare

Loan ownership share

owner Loan share owner.

percentage Percentage of loan owned by owner.

struct LoanShare {
    address owner;
    uint256 percentage;
}

ILoanConfigManager

Git Source

Inherits: ILoanManagerBase

Author: bull.haus

Manages all loan configurations.

Functions

createLoanConfig

Create loan configuration.

When collateral.interest is an empty array, collateral.acceptedInterest == collateral.acceptedCollateral.

Setting config.config.maxTotal to UINT_MAX disables maxTotal checks.

function createLoanConfig(LoanConfigUser calldata config, LoanConfigAssetUsage calldata assetUsage) external;

Parameters

NameTypeDescription
configLoanConfigUserloan configuration
assetUsageLoanConfigAssetUsageaccepted assets and their usage in the loan

deleteLoanConfig

Delete loan configuration.

Loan configurations can only be deleted when there are no open loans using this configuration.

function deleteLoanConfig(uint256 configId) external;

Parameters

NameTypeDescription
configIduint256configuration id of loan config to delete

updateLoanConfigEnabledStatus

Enable / disable loan configuration.

Loans can only be created for enabled loan configurations.

function updateLoanConfigEnabledStatus(uint256 configId, bool enabled) external;

Parameters

NameTypeDescription
configIduint256configuration id of loan config to enable / disable
enabledbooltrue to enable, false to disable

Events

LoanConfigCreated

Emitted when a loan configuration has been created.

event LoanConfigCreated(
    uint256 indexed configId, address indexed lender, uint256 indexed assetId, uint256 interestPromille, uint256 terms
);

LoanConfigDeleted

Emitted when a loan configuration has been deleted.

event LoanConfigDeleted(uint256 indexed configId);

LoanConfigEnabledStatusUpdated

Emitted when a loan configuration has been enabled / disabled.

event LoanConfigEnabledStatusUpdated(uint256 indexed configId, bool indexed enabled);

Errors

LoanConfigInUse

Deleting a loan config which has open loans, reverts with ConfigInUse.

error LoanConfigInUse();

InsufficientFunds

Creating loan configs with higher limits than currently in the lender's deposit reverts with InsufficientFunds.

error InsufficientFunds();

InvalidConfig

Creating loan configs with invalid configurations reverts with InvalidConfig.

See method's documentation for the meaning of each possible check value.

error InvalidConfig(uint256 check);

MaxConfigsReached

Creating more loan configs per asset than limits allow, reverts with MaxConfigsReached.

error MaxConfigsReached();

ILoanManager

Git Source

Inherits: ILoanManagerBase

Author: bull.haus

Manages all loans.

Functions

createLoan

Create loan, mint corresponding LoaNFT.

Maximum 10 loans per asset per user address.

Provided collateral assets are locked within the borrower's deposit, they are not transferred to the lender.

function createLoan(LoanInfoUser calldata config, CollateralAssets calldata collateralAssets) external;

Parameters

NameTypeDescription
configLoanInfoUserloan parameters
collateralAssetsCollateralAssetsprovided collateral and chosen asset configuration

pay

Pay back loan interest and/or principal.

Can be paid on behalf of another user.

Does not refund when too much interest is paid.

All interest payments go to the current holder of the corresponding LoaNFT.

Paid interest is taken from payee's unlocked deposit, and added to LoaNFT holder's unlocked deposit.

function pay(uint256 loanId, uint256[] calldata interestAssetAmount, uint256 principalAmount) external;

Parameters

NameTypeDescription
loanIduint256loan id to pay interest for
interestAssetAmountuint256[]amount of each asset to pay interest with
principalAmountuint256amount of principal to pay

liquidate

Liquidate a loan.

function liquidate(uint256 loanId) external;

Parameters

NameTypeDescription
loanIduint256loan id to liquidate.

setCollateral

Update collateral.

Collateral value should be at least the minimum collateral + safety buffer.

Collateral values are absolute numbers, values lower than the previously configured collateral result in unlocking of those assets.

Provided collateral assets are locked within the borrower's deposit, they are not transferred to the lender.

function setCollateral(uint256 loanId, uint256[] calldata assetAmount) external;

Parameters

NameTypeDescription
loanIduint256loan id to update collateral for
assetAmountuint256[]provided collateral amounts

Events

LoanCreated

Emitted when a loan is created.

event LoanCreated(uint256 configId, uint256 loanId);

LoanEvent

Emitted when an action is performed on a loan.

Actions are defined in LoanAction: interest paid, loan paid off, liquidated, collateral updated.

event LoanEvent(uint256 loanId, LoanAction action);

Errors

AssetUsageNotAllowed

When setting collateral or paying interest with assets not allowed per loan config, the transaction is reverted with AssetUsageNotAllowed.

error AssetUsageNotAllowed(uint256 check);

CannotLiquidate

When liquidating a loan that cannot be liquidated, the transaction is reverted with CannotLiquidate.

Check the liquidate method for details on the check value.

error CannotLiquidate(uint256 check);

LoanError

Loan with invalid parameters reverts with LoanError.

Check the methods returning this error for details on the check value.

error LoanError(uint256 check);

PrincipalTooLow

Reducing principal to a lower percentage of the initial principal, than the percentage of interest paid, is reverted with PrincipalTooLow.

error PrincipalTooLow();

Enums

LoanAction

Type of action being performed on a loan, used in events.

NoAction 0-value for invalid actions.

InterestPaid An interest payment has been done. This does not imply that the interest has been paid fully, or according to the loan plan.

PrincipalPaid A principal payment has been done. This does not imply that the principal has been paid fully, or according to the loan plan.

CollateralUpdated The collateral for a loan has been updated.

Liquidated A loan has been liquidated.

Closed A loan has been closed; all fees, interest and collateral has been paid, the LoaNFT shares have been deleted.

enum LoanAction {
    NoAction,
    InterestPaid,
    PrincipalPaid,
    CollateralUpdated,
    Liquidated,
    Closed
}

ILoanManagerBase

Git Source

Author: bull.haus

Base contract for loan actions containing all storage definitions.

Errors

NotAuthorized

Performing actions on other user's loan configs revert with NotAuthorized.

error NotAuthorized();

Structs

LoanConfigAssetUsage

Record containing all accepted asset ids and corresponding usage config.

All asset usages on loans (paying collateral, interest, changing collateral) have to use the exact same array of assets as defined upon creating a loan.

Loan configurations accept a list of price feeds (bitmask, where LSB is price feed index 0, MSB is price feed index 7).

assetId list of all accepted asset ids

priceFeedIndices list of all accepted price feed indices as bitfield (index 0 = LSB, index 7 = MSB)

useCollateral list of booleans indicating whether asset[i] can be used for collateral payments

useInterest list of booleans indicating whether asset[i] can be used for interest payments

struct LoanConfigAssetUsage {
    uint256[] assetId;
    uint8[] priceFeedIndices;
    bool[] useCollateral;
    bool[] useInterest;
}

CollateralAssets

List of collateral asset amounts and chosen price feed indices.

The array index corresponds to the arrays in LoanConfigAssetUsage.

amount list of collateral amounts for each asset. This value must be 0 when useCollateral == false for the corresponding asset.

priceFeedIndex chosen price feed index for each asset, where contrary to the bitfield in LoanConfigAssetUsage, this value is an integer value of exactly one chosen price feed. Only price feeds accepted in LoanConfigAssetUsage for this specific asset are allowed.

struct CollateralAssets {
    uint256[] amount;
    uint8[] priceFeedIndex;
}

LoanConfig

Contract-managed part of loan configurations.

The user-defined part is in LoanConfigUser and LoanAssets. Users cannot update this data, as it would change any ongoing loans. It should be deleted and re-created instead.

lender The creator of the loan config, and the initial lender of all loans created from this config.

enabled true when the loan config can be used for new loans, false otherwise.

totalLoanAmount Sum of loan amounts of all open loans created from this config.

config User-defined loan config settings.

assetUsage User-defined config asset usage settings.

struct LoanConfig {
    address lender;
    bool enabled;
    uint256 totalLoanAmount;
    LoanConfigUser config;
    LoanConfigAssetUsage assetUsage;
}

LoanConfigLimits

Platform limits to loan configurations.

These values are stored only once in the contract, but used in calculations many times. To avoid casting from uint8 to uint256, all values are stored as uint256.

minTerms: minimum amount of terms of a loan (1).

maxTerms: maximum amount of terms of a loan (10).

minInterestPromille: minimum interest rate in promille (percent * 10) (20).

maxInterestPromille: maximum interest rate in promille (percent * 10) (120).

interestPromilleResolution: interest rate resolution (interest rate % resolution == 0) (10).

minCollateralPercentageMinus100: minimum collateral percentage, minus "100" (20 == 120%).

maxCollateralPercentageMinus100: maximum collateral percentage, minus "100" (250 == 350%).

minSafetyBufferPercentage: minimum safety buffer percentage.

maxSafetyBufferPercentage: maximum safety buffer percentage.

maxLoanConfigsPerAsset: maximum amount of loan configurations per user per asset (10).

struct LoanConfigLimits {
    uint256 minTerms;
    uint256 maxTerms;
    uint256 minInterestPromille;
    uint256 maxInterestPromille;
    uint256 interestPromilleResolution;
    uint256 minCollateralPercentageMinus100;
    uint256 maxCollateralPercentageMinus100;
    uint256 minSafetyBufferPercentage;
    uint256 maxSafetyBufferPercentage;
    uint256 maxLoanConfigsPerAsset;
}

LoanConfigUser

Lender-defined part of loan configurations.

minLoanAmount: minimum amount of the loan asset per loan.

maxLoanAmount: maximum amount of the loan asset per loan.

maxTotalLoanAmount: maximum amount of open loans, taken for this specific loan config. Paid back loans are deducted from this value, if and only if the corresponding LoaNFT is held by LoanConfig.lender at the time of repayment.

assetId: loan asset id.

liquidationType: ignored in the current implementation, added for forward compatibility.

termPaymentType: required payments on each passing term; can be paid in advance.

acceptedPriceFeeds: accepted price feeds as bitmask.

interestPromille: interest of loan expressed in 0.1 percent (promille).

terms: amount of terms (30 days) for the loan.

collateralPercentageMinus100: minimum collateral percentage before liquidation, minus 100 (e.g. 0 = 100%, 50 = 150%, 100 = 200%).

safetyBufferPercentage: minimum safety buffer. Minimum collateral percentage when changing is collateralPercentageMinus100 + 100 + safetyBufferPercentage.

acceptSignedTerms: ignored in the current implementation, added for forward compatibility.

struct LoanConfigUser {
    uint256 minLoanAmount;
    uint256 maxLoanAmount;
    uint256 maxTotalLoanAmount;
    uint256 assetId;
    LiquidationType liquidationType;
    TermPaymentType termPaymentType;
    uint8 acceptedPriceFeeds;
    uint8 interestPromille;
    uint8 terms;
    uint8 collateralPercentageMinus100;
    uint8 safetyBufferPercentage;
    bool acceptSignedTerms;
}

LoanInfo

Contract-managed part of loans.

borrower: loan taker, collateral payer.

loanStart: block.timestamp of start of loan.

pendingPrincipalAmount: pending loan amount to repay.

pendingInterestAmount: pending amount of loan asset interest to repay.

loan: loan parameters as defined by borrower, within the limits of the lender-defined loan configuration.

collateralAssets: price feeds for all assets, and asset amounts for currently used collateral assets

struct LoanInfo {
    address borrower;
    uint256 loanStart;
    uint256 pendingPrincipalAmount;
    uint256 pendingInterestAmount;
    LoanInfoUser loan;
    CollateralAssets collateralAssets;
}

LoanInfoUser

Borrower-defined part of loans.

configId: configuration from which the loan is created.

loanAmount: amount of loan asset borrowed.

priceFeedIndex: chosen price feed index to determine current value for borrowed asset.

struct LoanInfoUser {
    uint256 configId;
    uint256 loanAmount;
    uint8 priceFeedIndex;
}

Enums

LiquidationType

Type of liquidation supported on loans taken from this configuration.

This is added for forward compatibility, as loans will be optionally non-liquidatable.

enum LiquidationType {
    None,
    All,
    Collateral
}

TermPaymentType

Type of required term payment on loans.

The option to pay only principal each term is not possible, as the platform has a hard requirement to pay at least the same interest share as principal share.

None: borrower is required to pay interest and principal only at the end of the loan.

Interest: borrower is required to pay a linear share of the total interest each term.

InterestAndPrincipal: borrower is required to pay a linear share of the total interest each term, as well as a linear share of the total principal.

enum TermPaymentType {
    None,
    Interest,
    InterestAndPrincipal
}

ILoanManagerDelegator

Git Source

Inherits: ILoanManager, ILoanConfigManager

Author: bull.haus

Delegator which forwards loan methods on delegatee contracts.

Loan contracts are split due to EIP-170 size restrictions. Calls are done within the storage context of the delegator contract.

Functions

initialize

Initialize deployed contract and set proxy contracts.

function initialize(
    address accessManager,
    ILoanConfigManager loanConfigManager,
    ILoanManager loanManager,
    IAssetManager assetManager_,
    ILoaNFT loaNFT_,
    LoanConfigLimits calldata limits_
) external;

Parameters

NameTypeDescription
accessManageraddressAccessManager authority instance.
loanConfigManagerILoanConfigManagerLoanConfigManager delegate contract address.
loanManagerILoanManagerLoanManager delegate contract address.
assetManager_IAssetManagerAssetManager contract address.
loaNFT_ILoaNFTLoaNFT contract address.
limits_LoanConfigLimitsPlatform limits for loan configs.

pause

Pause contract.

function pause() external;

unpause

Unpause contract.

function unpause() external;

getLoan

Get loan data.

function getLoan(uint256 loanId) external view returns (ILoanConfigManager.LoanInfo memory);

Parameters

NameTypeDescription
loanIduint256loan id to get loan data from

Returns

NameTypeDescription
<none>ILoanConfigManager.LoanInfoLoan info

getLoanAssets

Get loan asset data.

function getLoanAssets(uint256 loanId) external view returns (CollateralAssets memory);

Parameters

NameTypeDescription
loanIduint256loan id to get loan asset data for

getLoanConfig

Get loan accepted usage of asset for loan configuration.

function getLoanConfig(uint256 configId)
    external
    view
    returns (
        address lender,
        bool enabled,
        uint256 total,
        LoanConfigUser memory loanConfig,
        LoanConfigAssetUsage memory assetUsage
    );

Parameters

NameTypeDescription
configIduint256configuration id of loan config to get data from. Request ID 1 .. getLoanConfigCounter()

Returns

NameTypeDescription
lenderaddresslender owning loan config
enabledbooltrue when loan config is enabled, false when disabled
totaluint256sum of all currently open loans using this loan config
loanConfigLoanConfigUserloan config
assetUsageLoanConfigAssetUsageasset configuration for loan config

getLoanConfigCounter

Get loan configuration counter.

function getLoanConfigCounter() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256amount of loan configurations

getLoanCounter

Get loan counter.

function getLoanCounter() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256amount of loans

getUserConfigId

Get loan configuration id of user, by configuration index

Each user can configure up to 10 configurations per asset

function getUserConfigId(address lender, uint256 assetId, uint256 index) external view returns (uint256 configId);

Parameters

NameTypeDescription
lenderaddressuser address to get configuration id for
assetIduint256asset ID to get configuration id for
indexuint256index of configuration (0 .. 9)

Returns

NameTypeDescription
configIduint256loan configuration id at index. 0 when no loan configuration is stored at the given index.

IPriceFeedProxy

Git Source

Author: bull.haus

Generic API for reading price feed data from different oracles.

Functions

description

Get human-readable price feed proxy description.

function description() external view returns (string memory);

Returns

NameTypeDescription
<none>stringHuman-readable price feed proxy description.

Errors

ImplausiblePrice

Requesting a price, which results in an impossible price, reverts the transaction with ImplausiblePrice.

error ImplausiblePrice();

SequencerDown

When requesting a price on Layer 2 while the sequencer is down, reverts with SequencerDown.

As long as the sequencer is down, no transactions can be performed by the user. Preventing anything related to asset prices (e.g. liquidations) protects users.

error SequencerDown();

IPriceFeedProxyERC20

Git Source

Inherits: IPriceFeedProxy

Author: bull.haus

Generic API for reading ERC20 price feed data from different oracles.

Functions

getDollarPrice

Get the Dollar price of 1 asset unit.

1 asset unit is 1 ETH, 1 BTC, 1 USDT, etc.

function getDollarPrice(address priceFeedAddress) external view returns (uint256 timestamp, UD60x18 dollarPrice);

Parameters

NameTypeDescription
priceFeedAddressaddresscontract address of price feed

Returns

NameTypeDescription
timestampuint256time at which the returned value was determined
dollarPriceUD60x18price of 1 asset unit in Dollars (18 decimals)

ISequencer

Git Source

Author: bull.haus

Layer-2 sequencer interface to determine whether the network is currently running.

Functions

latestAnswer

Chainlink L2 sequencer.

function latestAnswer() external view returns (uint256);

Returns

NameTypeDescription
<none>uint2560 when sequencer is up, 1 when sequencer is down.

Contents

LoaNFT

Git Source

Inherits: ILoaNFT, AccessManagedUpgradeable, ERC1155Upgradeable, UUPSUpgradeable

Author: bull.haus

LoaNFT ERC1155 contract. Owners of LoaNFTs are (partial) lenders of loans on Lumin. LoaNFTs are transferrable.

Burning and minting of LoaNFTs is done by the LoanManager contract.

Each loan consists of 10 shares, each indicating 10% ownership of future payments of the loan.

State Variables

NUM_SHARES_PER_LOAN

Each loan ownership is split into 10 shares, each signifying a 10% ownership of the future payments.

uint256 private constant NUM_SHARES_PER_LOAN = 10;

nftOwners

Set of all LoaNFT IDs registered on the platform.

ERC1155 does not support owner(s)Of out of the box.

The maximum length is NUM_SHARES_PER_LOAN, for which calling EnumerableSet.value() in a state-changing method is acceptable.

mapping(uint256 => EnumerableSet.AddressSet) private nftOwners;

Functions

constructor

constructor();

initialize

Upgradeable contract initializer.

function initialize(address initialAdmin, string calldata uri) external initializer;

Parameters

NameTypeDescription
initialAdminaddressInitial admin of this contract. Can differ from the deployer.
uristringCollection URI.

mint

Mint LoaNFT token to given user address.

Can only be called by LoanManager.

function mint(address to, uint256 id) external restricted;

Parameters

NameTypeDescription
toaddressuser address to mint LoaNFT for
iduint256

burn

Burn LoaNFT token.

Can only be called by LoanManager.

function burn(uint256 id) external restricted;

Parameters

NameTypeDescription
iduint256

sharesOf

Get the owners and respective loan shares of each loan owner.

function sharesOf(uint256 id) external view returns (LoanShare[] memory shares);

Parameters

NameTypeDescription
iduint256

Returns

NameTypeDescription
sharesLoanShare[]List of owners and respective loan share of each loan owner

upgradeToAndCall

UUPS-upgrade contract.

function upgradeToAndCall(address newImplementation, bytes memory data) public payable override restricted;

Parameters

NameTypeDescription
newImplementationaddressAddress of newly deployed contract.
databytesInitial setup call data.

_authorizeUpgrade

Method is necessary for OZ's UUPSUpgradeable contracts.

function _authorizeUpgrade(address) internal pure override;

_update

Update list of loan owners on every token transfer, mint and burn action.

function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal override;

LoanConfigManager

Git Source

Inherits: LoanManagerBase, ILoanConfigManager

Author: bull.haus

Manages all loan configurations.

State Variables

NO_MAX_TOTAL

uint256 private constant NO_MAX_TOTAL = type(uint256).max;

Functions

createLoanConfig

Create loan configuration.

When collateral.interest is an empty array, collateral.acceptedInterest == collateral.acceptedCollateral.

function createLoanConfig(LoanConfigUser calldata config, LoanConfigAssetUsage calldata assetUsage) external;

Parameters

NameTypeDescription
configLoanConfigUserloan configuration
assetUsageLoanConfigAssetUsageaccepted assets and their usage in the loan

deleteLoanConfig

Delete loan configuration.

Loan configurations can only be deleted when there are no open loans using this configuration.

function deleteLoanConfig(uint256 configId) external;

Parameters

NameTypeDescription
configIduint256configuration id of loan config to delete

updateLoanConfigEnabledStatus

Enable / disable loan configuration.

Loans can only be created for enabled loan configurations.

function updateLoanConfigEnabledStatus(uint256 configId, bool enabled) external;

Parameters

NameTypeDescription
configIduint256configuration id of loan config to enable / disable
enabledbooltrue to enable, false to disable

LoanManager

Git Source

Inherits: LoanManagerBase, ILoanManager

Author: bull.haus

Manages all loans.

State Variables

TERM_DURATION

uint256 private constant TERM_DURATION = 30 days;

Functions

createLoan

Create loan, mint corresponding LoaNFT.

Maximum 10 loans per asset per user address.

function createLoan(LoanInfoUser calldata loan, CollateralAssets calldata collateralAssets) external;

Parameters

NameTypeDescription
loanLoanInfoUser
collateralAssetsCollateralAssetsprovided collateral and chosen asset configuration

pay

Pay back loan interest and/or principal.

Interest is paid first, after that the principal. This is due to the requirement to pay at least the same percentage of interest as principal. This requirement prevents borrowers to only reduce their principal to 0, remove all collateral and abandon their loan to never pay the interest.

function pay(uint256 loanId, uint256[] calldata interestAssetAmount, uint256 principalAmount) external;

Parameters

NameTypeDescription
loanIduint256loan id to pay interest for
interestAssetAmountuint256[]amount of each asset to pay interest with
principalAmountuint256amount of principal to pay

liquidate

Liquidate a loan.

Current implementation sends the full collateral to the lender.

Loans exist until (1) interest and (2) principal has been paid. Loans where (1) or (2) are open, can be liquidated.

function liquidate(uint256 loanId) external;

Parameters

NameTypeDescription
loanIduint256loan id to liquidate.

setCollateral

Update collateral.

Collateral value should be at least the minimum collateral + safety buffer.

function setCollateral(uint256 loanId, uint256[] calldata amount) external;

Parameters

NameTypeDescription
loanIduint256loan id to update collateral for
amountuint256[]

calculateLoanCollateral

Calculate Dollar value and collateral percentage of loan collateral.

UD60x18 is a fixed-point decimal value.

minCollateralShare is the minimum share for ongoing loans.

minCollateralAndSafetyBufferShare is the minimum share for newly created loans or changed collateral.

function calculateLoanCollateral(
    LoanInfo memory loan,
    uint256[] memory collateralAssetId,
    bool[] memory useCollateral,
    uint8[] memory priceFeedIndex,
    uint256[] memory amount
)
    private
    view
    returns (
        UD60x18 loanDollarValue,
        UD60x18 collateralDollarValue,
        UD60x18 collateralShare,
        UD60x18 minCollateralShare,
        UD60x18 minCollateralAndSafetyBufferShare
    );

Parameters

NameTypeDescription
loanLoanInfoloan parameters
collateralAssetIduint256[]list of asset ids
useCollateralbool[]list of booleans indicating whether the index can be used as collateral
priceFeedIndexuint8[]list of price feed indices
amountuint256[]list of asset amounts

Returns

NameTypeDescription
loanDollarValueUD60x18total Dollar value of the loan
collateralDollarValueUD60x18total Dollar value of the collateral
collateralShareUD60x18collateral share of loan value
minCollateralShareUD60x18minimum collateral share as defined in loan config
minCollateralAndSafetyBufferShareUD60x18minimum collateral + safety buffer share as defined in loan config

_payInterest

function _payInterest(uint256 loanId, uint256[] calldata interestAssetAmount, ILoaNFT.LoanShare[] memory loanShares)
    private;

_splitAssetTransferOnLoanAction

Split the payable amount over each loan owner, respecting their loan shares.

function _splitAssetTransferOnLoanAction(
    uint256 assetId,
    IAssetManager.AssetActionType action,
    address fromUserAddress,
    uint256 amount,
    ILoaNFT.LoanShare[] memory loanShares,
    bool distributeRemainder
) private;

Parameters

NameTypeDescription
assetIduint256Asset ID to pay.
actionIAssetManager.AssetActionTypeAction to perform on action.
fromUserAddressaddressUser address to taken amount assetId from.
amountuint256Amount Asset ID to pay.
loanSharesILoaNFT.LoanShare[]Loan owners and their respective loan ownership share.
distributeRemainderbooltrue if the possible remaining amount shall be sent to the first loan owner, false to leave the remaining amount in fromUserAddresss deposit.

_liquidate

function _liquidate(uint256 loanId, uint256[] memory assetId, uint256[] memory amount) private;

_cleanupLoan

function _cleanupLoan(uint256 loanId) private;

_assetValue

function _assetValue(uint256 assetId, uint256 priceFeedIndex, uint256 amount)
    private
    view
    returns (UD60x18 dollarValue, UD60x18 assetAmount);

LoanManagerBase

Git Source

Inherits: ILoanManagerBase

Author: bull.haus

Base contract for loan actions containing all storage definitions.

State Variables

assetManager

Reference to the asset manager contract, to (un)lock and transfer deposits.

IAssetManager internal assetManager;

loaNFT

Reference to the LoaNFT contract, to mint and burn LoaNFTs.

ILoaNFT internal loaNFT;

limits

Accepted value ranges for loan configs

LoanConfigLimits internal limits;

configCounter

Total amount of loan configurations.

This is implicitly the maximum available loan configuration ID, and is thus public.

uint256 public configCounter;

loanCounter

Total number of loans.

This number is the highest loan ID on this chain.

uint256 public loanCounter;

loanConfigs

Loan Config ID to Loan Config

mapping(uint256 => LoanConfig) internal loanConfigs;

userConfigIds

User to asset id => Loan Config ID

mapping(address => mapping(uint256 => EnumerableSet.UintSet)) internal userConfigIds;

loans

Loan ID to loan mapping

mapping(uint256 => LoanInfo) internal loans;

LoanManagerDelegator

Git Source

Inherits: LoanManagerBase, ILoanManagerDelegator, AccessManagedUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable, UUPSUpgradeable

Author: bull.haus

Delegator which forwards loan methods on delegatee contracts.

Loan contracts are split due to EIP-170 size restrictions. Calls are done within the storage context of the delegator contract.

State Variables

delegateLoanConfigManager

address private delegateLoanConfigManager;

delegateLoanManager

address private delegateLoanManager;

Functions

constructor

constructor();

initialize

Initialize deployed contract and set proxy contracts.

function initialize(
    address accessManager,
    ILoanConfigManager loanConfigManager,
    ILoanManager loanManager,
    IAssetManager assetManager_,
    ILoaNFT loaNFT_,
    LoanConfigLimits calldata limits_
) external initializer;

Parameters

NameTypeDescription
accessManageraddressAccessManager authority instance.
loanConfigManagerILoanConfigManagerLoanConfigManager delegate contract address.
loanManagerILoanManagerLoanManager delegate contract address.
assetManager_IAssetManagerAssetManager contract address.
loaNFT_ILoaNFTLoaNFT contract address.
limits_LoanConfigLimitsPlatform limits for loan configs.

createLoanConfig

Create loan configuration.

When collateral.interest is an empty array, collateral.acceptedInterest == collateral.acceptedCollateral.

function createLoanConfig(LoanConfigUser calldata config, LoanConfigAssetUsage calldata assetUsage) external;

Parameters

NameTypeDescription
configLoanConfigUserloan configuration
assetUsageLoanConfigAssetUsageaccepted assets and their usage in the loan

deleteLoanConfig

Delete loan configuration.

Loan configurations can only be deleted when there are no open loans using this configuration.

function deleteLoanConfig(uint256 configId) external;

Parameters

NameTypeDescription
configIduint256configuration id of loan config to delete

updateLoanConfigEnabledStatus

Enable / disable loan configuration.

Loans can only be created for enabled loan configurations.

function updateLoanConfigEnabledStatus(uint256 configId, bool enabled) external;

Parameters

NameTypeDescription
configIduint256configuration id of loan config to enable / disable
enabledbooltrue to enable, false to disable

pause

Pause contract.

function pause() external restricted whenNotPaused;

unpause

Unpause contract.

function unpause() external restricted whenPaused;

createLoan

Create loan, mint corresponding LoaNFT.

Maximum 10 loans per asset per user address.

function createLoan(LoanInfoUser calldata loan, CollateralAssets calldata collateralAssets) external nonReentrant;

Parameters

NameTypeDescription
loanLoanInfoUser
collateralAssetsCollateralAssetsprovided collateral and chosen asset configuration

pay

Pay back loan interest and/or principal.

Can be paid on behalf of another user.

function pay(uint256 loanId, uint256[] calldata interestAssetAmount, uint256 principalAmount) external nonReentrant;

Parameters

NameTypeDescription
loanIduint256loan id to pay interest for
interestAssetAmountuint256[]amount of each asset to pay interest with
principalAmountuint256amount of principal to pay

liquidate

Liquidate a loan.

function liquidate(uint256 loanId) external nonReentrant;

Parameters

NameTypeDescription
loanIduint256loan id to liquidate.

setCollateral

Update collateral.

Collateral value should be at least the minimum collateral + safety buffer.

function setCollateral(uint256 loanId, uint256[] calldata amount) external;

Parameters

NameTypeDescription
loanIduint256loan id to update collateral for
amountuint256[]

upgradeToAndCall

UUPS-upgrade contract.

function upgradeToAndCall(address newImplementation, bytes memory data) public payable override restricted whenPaused;

Parameters

NameTypeDescription
newImplementationaddressAddress of newly deployed contract.
databytesInitial setup call data.

getLoan

Get loan data.

function getLoan(uint256 loanId) external view returns (LoanInfo memory);

Parameters

NameTypeDescription
loanIduint256loan id to get loan data from

Returns

NameTypeDescription
<none>LoanInfoLoan info

getLoanAssets

Get loan asset data.

function getLoanAssets(uint256 loanId) external view returns (CollateralAssets memory);

Parameters

NameTypeDescription
loanIduint256loan id to get loan asset data for

getLoanConfig

Get loan accepted usage of asset for loan configuration.

function getLoanConfig(uint256 configId)
    external
    view
    returns (
        address lender,
        bool enabled,
        uint256 total,
        LoanConfigUser memory loanConfig,
        LoanConfigAssetUsage memory assetUsage
    );

Parameters

NameTypeDescription
configIduint256configuration id of loan config to get data from. Request ID 1 .. getLoanConfigCounter()

Returns

NameTypeDescription
lenderaddresslender owning loan config
enabledbooltrue when loan config is enabled, false when disabled
totaluint256sum of all currently open loans using this loan config
loanConfigLoanConfigUserloan config
assetUsageLoanConfigAssetUsageasset configuration for loan config

getLoanConfigCounter

Get loan configuration counter.

function getLoanConfigCounter() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256amount of loan configurations

getLoanCounter

Get loan counter.

function getLoanCounter() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256amount of loans

getUserConfigId

Get loan configuration id of user, by configuration index

Each user can configure up to 10 configurations per asset

function getUserConfigId(address lender, uint256 assetId, uint256 index) external view returns (uint256);

Parameters

NameTypeDescription
lenderaddressuser address to get configuration id for
assetIduint256asset ID to get configuration id for
indexuint256index of configuration (0 .. 9)

Returns

NameTypeDescription
<none>uint256configId loan configuration id at index. 0 when no loan configuration is stored at the given index.

_authorizeUpgrade

Allow upgrades when contract is paused.

Method is necessary for OZ's UUPSUpgradeable contracts.

function _authorizeUpgrade(address) internal pure override;

_delegateCall

function _delegateCall(address delegatee, bytes memory _data) private whenNotPaused;

Contents

PriceFeedProxyChainlink

Git Source

Inherits: IPriceFeedProxyERC20, AccessManagedUpgradeable, UUPSUpgradeable

Author: bull.haus

Chainlink price feed proxy for ERC20 assets on L1 and L2 chains.

State Variables

description

Human-readable proxy description.

Public to auto-generate getter.

string public description;

sequencer

ISequencer private sequencer;

Functions

constructor

constructor();

initialize

Upgradeable contract initializer.

function initialize(address initialAdmin, string memory description_, ISequencer sequencer_) external initializer;

Parameters

NameTypeDescription
initialAdminaddressInitial admin of this contract. Can differ from the deployer.
description_stringhuman-readable description of price feed proxy
sequencer_ISequencerL2 sequencer address, use address(0) when no sequencer is available

upgradeToAndCall

UUPS-upgrade contract.

function upgradeToAndCall(address newImplementation, bytes memory data) public payable override restricted;

Parameters

NameTypeDescription
newImplementationaddressAddress of newly deployed contract.
databytesInitial setup call data.

getDollarPrice

Get the Dollar price of 1 asset unit.

The sequencer validation is skipped when the chain does not have a sequencer.

function getDollarPrice(address priceFeedAddress) external view returns (uint256 timestamp, UD60x18 dollarPrice);

Parameters

NameTypeDescription
priceFeedAddressaddresscontract address of price feed

Returns

NameTypeDescription
timestampuint256time at which the returned value was determined
dollarPriceUD60x18price of 1 asset unit in Dollars (18 decimals)

_authorizeUpgrade

Method is necessary for OZ's UUPSUpgradeable contracts.

function _authorizeUpgrade(address) internal pure override;