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 loanenabled
: true when the loan configuration is currently active, false otherwise. Loans cannot be taken on disabled configurationstotalLoanAmount
: total amount currently being lent and not paid back to thelender
of all loans using this loan configuration. Note that NFTs not owned bylender
lead to not deducingtotal
upon paying back the loan. The rationale for this is that the lent asset is not put back into thelender
's deposit upon payback.minLoanAmount
: minimum amount that can be borrowed per loanmaxLoanAmount
: maximum amount that can be borrowed per loanmaxTotalLoanAmount
: maximum value oftotal
; loans can only be taken for this loan configuration as long astotal
does not exceedmaxTotal
assetId
: asset ID to lendliquidationType
: not yet implementedtermPaymentType
: whether the borrower shall pay a linear share of the interest, or interest and principal, each termacceptedPriceFeeds
: bit field indicating which price feeds are allowed to be used to determine the value of the loaninterestPromille
: interest percentage * 10 (5.6% = 56 promille, 11% = 110 promille)terms
: loan duration expressed in terms (seeTERM_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 LoaNFT
s are minted. When the loan has been closed, the LoaNFT
s 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
LoaNFT
s 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
LoaNFT
s to the lender upon creating a loan. - LoanManager burns 10
LoaNFT
s 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 correspondingLoaNFT
shares, each signifying a 10% ownership of the loan.
After the collateral is split, the loan and corresponding LoaNFT
s 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
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
Name | Type | Description |
---|---|---|
initialAdmin | address | Initial 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
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
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 ID
s 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) Deposit
s.
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
Name | Type | Description |
---|---|---|
initialAdmin | address | Initial 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
Name | Type | Description |
---|---|---|
<none> | AssetType | |
assetAddress | address | contract address of added asset |
symbol | string | asset 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
Name | Type | Description |
---|---|---|
assetId | uint256 | unique asset identifier |
enabled | bool | true 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to deposit or withdraw |
action | AssetActionType | asset action to perform (AssetActionType.Deposit, AssetActionType.Withdraw) |
amount | uint256 | amount 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to transfer |
action | AssetActionType | action to perform |
userAddressFrom | address | address to transfer asset from |
userAddressTo | address | address to transfer asset to |
amount | uint256 | to 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to (un)lock |
action | AssetActionType | lock / unlock |
userAddress | address | user address to (un)lock for |
amount | uint256 | amount to (un)lock |
setPriceFeedProxy
Set price feed proxy address
function setPriceFeedProxy(uint256 index, address priceFeedProxyAddress) external restricted;
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | index to store price feed proxy at |
priceFeedProxyAddress | address | address 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
Name | Type | Description |
---|---|---|
index | uint256 | price feed proxy index |
enabled | bool | true 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to set price feed for |
priceFeedIndex | uint256 | index of price feed to set |
priceFeedAddress | address | address 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to enable/disable price feed for |
priceFeedIndex | uint256 | index of price feed to set |
enabled | bool | true to enable, false to disable |
upgradeToAndCall
UUPS-upgrade contract.
function upgradeToAndCall(address newImplementation, bytes memory data) public payable override restricted whenPaused;
Parameters
Name | Type | Description |
---|---|---|
newImplementation | address | Address of newly deployed contract. |
data | bytes | Initial 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
Name | Type | Description |
---|---|---|
<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
Name | Type | Description |
---|---|---|
assetId | uint256 | id of asset |
userAddress | address | user's address to get deposit for |
Returns
Name | Type | Description |
---|---|---|
userDeposit | DepositData | Deposit 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
Name | Type | Description |
---|---|---|
userAddress | address | user's address to get balances for. address(0) for asset totals. |
Returns
Name | Type | Description |
---|---|---|
assetIds | uint256[] | Ordered list of asset ids for which balances are returned |
depositsTotal | DepositData[] | Ordered list of total Deposit s |
depositsUser | DepositData[] | Ordered list of Deposit s of userAddress |
balances | uint256[] | 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
Name | Type | Description |
---|---|---|
<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
Name | Type | Description |
---|---|---|
index | uint256 | index to get price feed proxy address from |
Returns
Name | Type | Description |
---|---|---|
<none> | address | address 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset ID to find information for |
Returns
Name | Type | Description |
---|---|---|
asset | Asset | asset details |
priceFeeds | EnabledAddress[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
- IAssetManager
- IAssetManager constants
- ILoaNFT
- ILoanConfigManager
- ILoanManager
- ILoanManagerBase
- ILoanManagerDelegator
- IPriceFeedProxy
- IPriceFeedProxyERC20
- ISequencer
IAggregatorV3
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
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
Name | Type | Description |
---|---|---|
assetType | AssetType | type of added asset |
assetAddress | address | contract address of added asset |
symbol | string | asset symbol (e.g. BTC, ETH) |
collectionId | uint256 | id 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
Name | Type | Description |
---|---|---|
assetId | uint256 | unique asset identifier |
enabled | bool | true 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to deposit or withdraw |
action | AssetActionType | asset action to perform (AssetActionType.Deposit, AssetActionType.Withdraw) |
amount | uint256 | amount 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to transfer |
action | AssetActionType | action to perform |
userAddressFrom | address | address to transfer asset from |
userAddressTo | address | address to transfer asset to |
amount | uint256 | to transfer |
assetLockUnlock
Lock / unlock asset.
This method is called by the LoanManager
function assetLockUnlock(uint256 assetId, AssetActionType action, address userAddress, uint256 amount) external;
Parameters
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to (un)lock |
action | AssetActionType | lock / unlock |
userAddress | address | user address to (un)lock for |
amount | uint256 | amount to (un)lock |
setPriceFeedProxy
Set price feed proxy address
function setPriceFeedProxy(uint256 index, address priceFeedProxyAddress) external;
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | index to store price feed proxy at |
priceFeedProxyAddress | address | address 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
Name | Type | Description |
---|---|---|
index | uint256 | price feed proxy index |
enabled | bool | true 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to set price feed for |
priceFeedIndex | uint256 | index of price feed to set |
priceFeedAddress | address | address 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset id to enable/disable price feed for |
priceFeedIndex | uint256 | index of price feed to set |
enabled | bool | true 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
Name | Type | Description |
---|---|---|
<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
Name | Type | Description |
---|---|---|
assetId | uint256 | id of asset |
userAddress | address | user's address to get deposit for |
Returns
Name | Type | Description |
---|---|---|
userDeposit | DepositData | Deposit 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
Name | Type | Description |
---|---|---|
userAddress | address | user's address to get balances for. address(0) for asset totals. |
Returns
Name | Type | Description |
---|---|---|
assetIds | uint256[] | Ordered list of asset ids for which balances are returned |
depositsTotal | DepositData[] | Ordered list of total Deposit s |
depositsUser | DepositData[] | Ordered list of Deposit s of userAddress |
balances | uint256[] | 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
Name | Type | Description |
---|---|---|
<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
Name | Type | Description |
---|---|---|
index | uint256 | index to get price feed proxy address from |
Returns
Name | Type | Description |
---|---|---|
<none> | address | address 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
Name | Type | Description |
---|---|---|
assetId | uint256 | asset ID to find information for |
Returns
Name | Type | Description |
---|---|---|
asset | Asset | asset details |
priceFeeds | EnabledAddress[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
MAX_PRICE_FEED_PROXIES
uint256 constant MAX_PRICE_FEED_PROXIES = 8;
ILoaNFT
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
Name | Type | Description |
---|---|---|
to | address | user address to mint LoaNFT for |
tokenId | uint256 | LoaNFT 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
Name | Type | Description |
---|---|---|
tokenId | uint256 | LoaNFT 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
Name | Type | Description |
---|---|---|
tokenId | uint256 | LoaNFT token identifier for which to get loan ownership shares |
Returns
Name | Type | Description |
---|---|---|
shares | LoanShare[] | 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
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
Name | Type | Description |
---|---|---|
config | LoanConfigUser | loan configuration |
assetUsage | LoanConfigAssetUsage | accepted 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
Name | Type | Description |
---|---|---|
configId | uint256 | configuration 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
Name | Type | Description |
---|---|---|
configId | uint256 | configuration id of loan config to enable / disable |
enabled | bool | true 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
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
Name | Type | Description |
---|---|---|
config | LoanInfoUser | loan parameters |
collateralAssets | CollateralAssets | provided 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
Name | Type | Description |
---|---|---|
loanId | uint256 | loan id to pay interest for |
interestAssetAmount | uint256[] | amount of each asset to pay interest with |
principalAmount | uint256 | amount of principal to pay |
liquidate
Liquidate a loan.
function liquidate(uint256 loanId) external;
Parameters
Name | Type | Description |
---|---|---|
loanId | uint256 | loan 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
Name | Type | Description |
---|---|---|
loanId | uint256 | loan id to update collateral for |
assetAmount | uint256[] | 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
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
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
Name | Type | Description |
---|---|---|
accessManager | address | AccessManager authority instance. |
loanConfigManager | ILoanConfigManager | LoanConfigManager delegate contract address. |
loanManager | ILoanManager | LoanManager delegate contract address. |
assetManager_ | IAssetManager | AssetManager contract address. |
loaNFT_ | ILoaNFT | LoaNFT contract address. |
limits_ | LoanConfigLimits | Platform 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
Name | Type | Description |
---|---|---|
loanId | uint256 | loan id to get loan data from |
Returns
Name | Type | Description |
---|---|---|
<none> | ILoanConfigManager.LoanInfo | Loan info |
getLoanAssets
Get loan asset data.
function getLoanAssets(uint256 loanId) external view returns (CollateralAssets memory);
Parameters
Name | Type | Description |
---|---|---|
loanId | uint256 | loan 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
Name | Type | Description |
---|---|---|
configId | uint256 | configuration id of loan config to get data from. Request ID 1 .. getLoanConfigCounter() |
Returns
Name | Type | Description |
---|---|---|
lender | address | lender owning loan config |
enabled | bool | true when loan config is enabled, false when disabled |
total | uint256 | sum of all currently open loans using this loan config |
loanConfig | LoanConfigUser | loan config |
assetUsage | LoanConfigAssetUsage | asset configuration for loan config |
getLoanConfigCounter
Get loan configuration counter.
function getLoanConfigCounter() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | amount of loan configurations |
getLoanCounter
Get loan counter.
function getLoanCounter() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | amount 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
Name | Type | Description |
---|---|---|
lender | address | user address to get configuration id for |
assetId | uint256 | asset ID to get configuration id for |
index | uint256 | index of configuration (0 .. 9) |
Returns
Name | Type | Description |
---|---|---|
configId | uint256 | loan configuration id at index. 0 when no loan configuration is stored at the given index. |
IPriceFeedProxy
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
Name | Type | Description |
---|---|---|
<none> | string | Human-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
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
Name | Type | Description |
---|---|---|
priceFeedAddress | address | contract address of price feed |
Returns
Name | Type | Description |
---|---|---|
timestamp | uint256 | time at which the returned value was determined |
dollarPrice | UD60x18 | price of 1 asset unit in Dollars (18 decimals) |
ISequencer
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
Name | Type | Description |
---|---|---|
<none> | uint256 | 0 when sequencer is up, 1 when sequencer is down. |
Contents
LoaNFT
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
Name | Type | Description |
---|---|---|
initialAdmin | address | Initial admin of this contract. Can differ from the deployer. |
uri | string | Collection URI. |
mint
Mint LoaNFT token to given user address.
Can only be called by LoanManager.
function mint(address to, uint256 id) external restricted;
Parameters
Name | Type | Description |
---|---|---|
to | address | user address to mint LoaNFT for |
id | uint256 |
burn
Burn LoaNFT token.
Can only be called by LoanManager.
function burn(uint256 id) external restricted;
Parameters
Name | Type | Description |
---|---|---|
id | uint256 |
sharesOf
Get the owners and respective loan shares of each loan owner.
function sharesOf(uint256 id) external view returns (LoanShare[] memory shares);
Parameters
Name | Type | Description |
---|---|---|
id | uint256 |
Returns
Name | Type | Description |
---|---|---|
shares | LoanShare[] | 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
Name | Type | Description |
---|---|---|
newImplementation | address | Address of newly deployed contract. |
data | bytes | Initial 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
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
Name | Type | Description |
---|---|---|
config | LoanConfigUser | loan configuration |
assetUsage | LoanConfigAssetUsage | accepted 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
Name | Type | Description |
---|---|---|
configId | uint256 | configuration 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
Name | Type | Description |
---|---|---|
configId | uint256 | configuration id of loan config to enable / disable |
enabled | bool | true to enable, false to disable |
LoanManager
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
Name | Type | Description |
---|---|---|
loan | LoanInfoUser | |
collateralAssets | CollateralAssets | provided 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
Name | Type | Description |
---|---|---|
loanId | uint256 | loan id to pay interest for |
interestAssetAmount | uint256[] | amount of each asset to pay interest with |
principalAmount | uint256 | amount 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
Name | Type | Description |
---|---|---|
loanId | uint256 | loan 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
Name | Type | Description |
---|---|---|
loanId | uint256 | loan id to update collateral for |
amount | uint256[] |
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
Name | Type | Description |
---|---|---|
loan | LoanInfo | loan parameters |
collateralAssetId | uint256[] | list of asset ids |
useCollateral | bool[] | list of booleans indicating whether the index can be used as collateral |
priceFeedIndex | uint8[] | list of price feed indices |
amount | uint256[] | list of asset amounts |
Returns
Name | Type | Description |
---|---|---|
loanDollarValue | UD60x18 | total Dollar value of the loan |
collateralDollarValue | UD60x18 | total Dollar value of the collateral |
collateralShare | UD60x18 | collateral share of loan value |
minCollateralShare | UD60x18 | minimum collateral share as defined in loan config |
minCollateralAndSafetyBufferShare | UD60x18 | minimum 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
Name | Type | Description |
---|---|---|
assetId | uint256 | Asset ID to pay. |
action | IAssetManager.AssetActionType | Action to perform on action. |
fromUserAddress | address | User address to taken amount assetId from. |
amount | uint256 | Amount Asset ID to pay. |
loanShares | ILoaNFT.LoanShare[] | Loan owners and their respective loan ownership share. |
distributeRemainder | bool | true if the possible remaining amount shall be sent to the first loan owner, false to leave the remaining amount in fromUserAddress s 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
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
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
Name | Type | Description |
---|---|---|
accessManager | address | AccessManager authority instance. |
loanConfigManager | ILoanConfigManager | LoanConfigManager delegate contract address. |
loanManager | ILoanManager | LoanManager delegate contract address. |
assetManager_ | IAssetManager | AssetManager contract address. |
loaNFT_ | ILoaNFT | LoaNFT contract address. |
limits_ | LoanConfigLimits | Platform 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
Name | Type | Description |
---|---|---|
config | LoanConfigUser | loan configuration |
assetUsage | LoanConfigAssetUsage | accepted 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
Name | Type | Description |
---|---|---|
configId | uint256 | configuration 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
Name | Type | Description |
---|---|---|
configId | uint256 | configuration id of loan config to enable / disable |
enabled | bool | true 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
Name | Type | Description |
---|---|---|
loan | LoanInfoUser | |
collateralAssets | CollateralAssets | provided 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
Name | Type | Description |
---|---|---|
loanId | uint256 | loan id to pay interest for |
interestAssetAmount | uint256[] | amount of each asset to pay interest with |
principalAmount | uint256 | amount of principal to pay |
liquidate
Liquidate a loan.
function liquidate(uint256 loanId) external nonReentrant;
Parameters
Name | Type | Description |
---|---|---|
loanId | uint256 | loan 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
Name | Type | Description |
---|---|---|
loanId | uint256 | loan id to update collateral for |
amount | uint256[] |
upgradeToAndCall
UUPS-upgrade contract.
function upgradeToAndCall(address newImplementation, bytes memory data) public payable override restricted whenPaused;
Parameters
Name | Type | Description |
---|---|---|
newImplementation | address | Address of newly deployed contract. |
data | bytes | Initial setup call data. |
getLoan
Get loan data.
function getLoan(uint256 loanId) external view returns (LoanInfo memory);
Parameters
Name | Type | Description |
---|---|---|
loanId | uint256 | loan id to get loan data from |
Returns
Name | Type | Description |
---|---|---|
<none> | LoanInfo | Loan info |
getLoanAssets
Get loan asset data.
function getLoanAssets(uint256 loanId) external view returns (CollateralAssets memory);
Parameters
Name | Type | Description |
---|---|---|
loanId | uint256 | loan 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
Name | Type | Description |
---|---|---|
configId | uint256 | configuration id of loan config to get data from. Request ID 1 .. getLoanConfigCounter() |
Returns
Name | Type | Description |
---|---|---|
lender | address | lender owning loan config |
enabled | bool | true when loan config is enabled, false when disabled |
total | uint256 | sum of all currently open loans using this loan config |
loanConfig | LoanConfigUser | loan config |
assetUsage | LoanConfigAssetUsage | asset configuration for loan config |
getLoanConfigCounter
Get loan configuration counter.
function getLoanConfigCounter() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | amount of loan configurations |
getLoanCounter
Get loan counter.
function getLoanCounter() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | amount 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
Name | Type | Description |
---|---|---|
lender | address | user address to get configuration id for |
assetId | uint256 | asset ID to get configuration id for |
index | uint256 | index of configuration (0 .. 9) |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | configId 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
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
Name | Type | Description |
---|---|---|
initialAdmin | address | Initial admin of this contract. Can differ from the deployer. |
description_ | string | human-readable description of price feed proxy |
sequencer_ | ISequencer | L2 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
Name | Type | Description |
---|---|---|
newImplementation | address | Address of newly deployed contract. |
data | bytes | Initial 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
Name | Type | Description |
---|---|---|
priceFeedAddress | address | contract address of price feed |
Returns
Name | Type | Description |
---|---|---|
timestamp | uint256 | time at which the returned value was determined |
dollarPrice | UD60x18 | price of 1 asset unit in Dollars (18 decimals) |
_authorizeUpgrade
Method is necessary for OZ's UUPSUpgradeable
contracts.
function _authorizeUpgrade(address) internal pure override;