TinteroLoan
Inherits: Initializable, UUPSUpgradeable, TinteroLoanView Author: Ernesto García Loan that uses an ERC721 token as collateral. The loan is funded with an ERC20 token and structured in a series of payments and tranches they belong to. This contract behaves as a state machine with the following states:- CREATED: The loan has been initialized and payments or tranches are being added.
- CANCELED: The loan has been canceled and the collateral is being withdrawn.
- FUNDING: The loan is being funded by the liquidity provider.
- ONGOING: The loan has been funded and the payments are being repaid.
- DEFAULTED: The loan has defaulted and the collateral can be repossessed.
- REPOSSESSED: The collateral is being repossessed by the liquidity provider.
- PAID: The loan has been fully repaid.
Concepts
- Payments: A payment is a structure that represents a payment to be made back to the loan. Each payment has a principal amount and an interest rate that is accrued over time in a linear fashion. A premium rate is added to the interest rate after the payment is due (at maturity).
- Tranches: A tranche is a collection of payments that have the same recipient. They are used to sell parts of the loan to different investors.
- Collateral: The collateral is an ERC721 token that is used to back the payments. A payment’s collateral can be repossessed if the loan defaults after a default threshold.
Users must approve this contract to transfer their ERC-721 tokens used as collateral.
This may allow a malicious actor to transfer request a loan and transferring their tokens
to this contract unexpectedly. For those cases, the original owner can retake their collateral
with the
withdrawPaymentCollateral
function.security-contact: security@plumaa.id
Functions
onlyLiquidityProvider
Reverts if the caller is not the loan’s liquidity provideronlyBeneficiary
Reverts if the caller is not the loan’s beneficiaryconstructor
Note: oz-upgrades-unsafe-allow: constructorinitialize
Initializes the loan with the provided parameters.Name | Type | Description |
---|---|---|
liquidityProvider_ | address | The address funding the loan. |
collateralAsset_ | address | The ERC721 token used as collateral. |
beneficiary_ | address | The address to receive the principal once funded. |
defaultThreshold_ | uint24 | The number of missed payments at which the loan defaults. |
pushPayments
*Adds a list of payments to the loan. Requirements:- The caller MUST be the liquidity provider.
- The loan MUST be in CREATED state.
- The collateral tokenIds and payments arrays MUST have the same length.
- The payments MUST be ordered by maturity date.
- The payments MUST NOT have matured.
- The collateral tokenIds MUST NOT have been added before.
- The collateralTokenIds MUST exist.
- The owner of each collateral tokenId MUST have approved this contract to transfer it (if not the contract itself).
- The
totalPayments
is incremented by the length of the payments array. - The
collateralTokenIds
are transferred to this contract. - The
payment
function will return the added payments at their corresponding indexes starting attotalPayments
. - Emits a
PaymentCreated
event for each payment added.*
pushTranches
*Adds a list of tranches to the loan. Requirements:- The caller MUST be the liquidity provider.
- The loan MUST be in CREATED state.
- The paymentIndexes and recipients arrays MUST have the same length.
- The tranche indexes MUST be strictly increasing.
- The total number of tranches MUST be less than the total number of payments.
- The
totalTranches
is incremented by the length of the tranches array. - The
tranche
function will return the added tranches at their corresponding indexes starting attotalTranches
. - The tranches are added to the loan.
- Emits a
TrancheCreated
event for each tranche added.*
fundN
*Fundsn
payments from the loan.
Requirements:
- The loan MUST be in CREATED or FUNDING state.
- Tranches MUST include all payments.
- The caller MUST have enough funds to fund the payments
- This contract mus have been approved to transfer the principal amount from the caller.
- Moves to FUNDING state
- Moves to ONGOING state if all payments are funded.
- The
currentFundingIndex
is incremented byn
or the remaining payments. - The principal of the funded payments is transferred from the liquidity provider to the beneficiary.
- Sets the
fundedAt
field of the funded payments to the current block timestamp. - Emits a
PaymentsFunded
event with the range of funded payments.*
withdrawPaymentCollateral
*Withdraws the collateral to the beneficiary. Requirements:- The loan MUST be in CREATED or CANCELED state.
- Each payment collateral MUST be owned by this contract.
- The caller MUST be the beneficiary.
- Moves to CANCELED state.
- Each payment collateral is transferred to the beneficiary.
- Emits a
PaymentsWithdrawn
with the range of payments withdrawn*
repayCurrent
Same asrepayN(0, collateralReceiver)
.
repayN
*Repays the current loan andn
future payments.
Requirements:
- The loan MUST be in ONGOING or DEFAULTED state.
- The sender MUST have enough funds to repay the principal of the specified payments
- The sender MUST have approved this contract to transfer the principal amount
- The collateral MUST be owned by this contract.
- Moves to ONGOING if paid until below the default threshold.
- Moves to PAID state if all payments are repaid.
- The
currentPaymentIndex
is incremented byn
or the remaining payments. - The principal of the repaid payments is transferred from the sender to the receiver of each payment tranche
- The collateral is transferred to the collateralReceiver if provided, otherwise it is burned.
- Emits a
PaymentsRepaid
event with the range of repaid payments.*
repossess
*Repossess the collateral from payments. Requirements:- The loan MUST be in DEFAULTED or REPOSSESSED state.
- The caller MUST be the liquidity provider.
- The collateral MUST be owned by this contract.
- The receiver MUST implement IERC721Receiver to receive the collateral.
- Moves to REPOSSESSED state.
- The collateral is transferred to the receiver.
- Emits a
PaymentsRepossessed
event with the range of repossessed payments.*
_validatePushPaymentsAndCollectCollateral
*Performs validations on the payments to be added to the loan. Requirements:- The collateral tokenIds and payments arrays MUST have the same length.
- The payments MUST be ordered by maturity date.
- The payments
fundedAt
field MUST be 0. - The payments MUST NOT have matured.
- The collateral tokenIds MUST NOT have been added before.
- The collateralTokenIds MUST exist.
- The owner of each collateral tokenId MUST have approved this contract to transfer it (if not the contract itself).
- The
totalPayments
is incremented by the length of the payments array. - The
collateralTokenIds
are transferred to this contract. - The
payment
function will return the added payments at their corresponding indexes starting attotalPayments
. - Emits a
PaymentCreated
event for each payment added.*
_validateAndPushTranches
*Validates the tranches and adds them to the loan. Requirements:- The paymentIndexes and recipients arrays MUST have the same length.
- The tranche indexes MUST be strictly increasing.
- The total number of tranches MUST be less than the total number of payments.
- The
totalTranches
is incremented by the length of the tranches array. - The
tranche
function will return the added tranches at their corresponding indexes starting attotalTranches
. - The tranches are added to the loan.
- Emits a
TrancheCreated
event for each tranche added.*
_validatePushPayment
*Validates the payment and adds it to the loan. Requirements:- The payment
fundedAt
field MUST be 0. - The payment maturity date MUST NOT be before the latest maturity.
- The payment MUST NOT have matured.
- The collateral tokenId MUST not have been added before.
- The
totalPayments
is incremented by 1. - The
payment
function will return the added_payment
after the currenttotalPayments
. - Emits a
PaymentCreated
event.*
_collectCollateral
*Checks if the tokenId is owned by this contract and transfers it to this contract otherwise. Requirements:- The collateralTokenIds MUST exist.
- The owner of each collateral tokenId MUST have approved this contract to transfer it (if not the contract itself).
- The
collateralTokenIds
are transferred to this contract.*
_fundN
*Fundsn
payments from the loan. Returns the total principal to fund.
The end
index is capped to the total number of payments.
Effects:
- Moves to FUNDING state
- Moves to ONGOING state if all payments are funded.
- The
currentFundingIndex
is incremented byn
or the remaining payments. - The principal of the funded payments is transferred from the liquidity provider to the beneficiary.
- Sets the
fundedAt
field of the funded payments to the current block timestamp.*
_withdrawPaymentCollateral
*Withdraws the collateral to the beneficiary. Requirements:- Each payment collateral MUST be owned by this contract.
- Moves to CANCELED state.
- The payment collateral is transferred to the beneficiary.
- Emits a
PaymentsWithdrawn
event.*
_repay
*Repays the current loan andn
future payments.
Requirements:
- The sender MUST have enough funds to repay the principal of the specified payments
- The sender MUST have approved this contract to transfer the principal amount
- The collateral MUST be owned by this contract.
- Moves to ONGOING if paid until below the default threshold.
- Moves to PAID state if all payments are repaid.
- The
currentPaymentIndex
is incremented byn
or the remaining payments. - The principal of the repaid payments is transferred from the sender to the receiver of each payment tranche
- The collateral is transferred to the collateralReceiver if provided, otherwise it is burned.
- Emits a
PaymentsRepaid
event with the range of repaid payments.*
_repossess
*Repossess the collateral from payments. Requirements:- The collateral MUST be owned by this contract.
- The receiver MUST implement IERC721Receiver to receive the collateral.
- Moves to REPOSSESSED state.
- The collateral is transferred to the receiver.
- Emits a
PaymentsRepossessed
event with the range of repossessed payments.*
upgradeLoan
Upgrades the loan to a new implementation. Useful for renegotiating terms._authorizeUpgrade
_validateStateBitmap
Check that the current state of the loan matches the requirements described by theallowedStates
bitmap. Otherwise, reverts with an UnexpectedLoanState error.
This bitmap should be built using _encodeStateBitmap
.
_encodeStateBitmap
*Encodes aLoanState
into a bytes32
representation where each bit enabled corresponds to
the underlying position in the LoanState
enum. For example:
_repayByTranches
*Repays the payments fromstart
to end
by doing a single transfer per tranche.
Assumes end is not greater than the total number of payments.
Requirements:
- The sender MUST have enough funds to repay the principal of the specified payments
- The sender MUST have approved this contract to transfer the principal amount
- The principal of the repaid payments is transferred from the sender to the receiver of each payment tranche
- Moves to ONGOING if paid until below the default threshold.
- Moves to PAID state if all payments are repaid.
- Emits a
PaymentsRepaid
event with the range of repaid payments.*
_prepareToPay
*Prepares the loan for repayment ofn
payments. Returns the total amount to pay.
Assumes end is not greater than the total number of payments.
Effects:
- Moves to ONGOING if paid until below the default threshold.
- Moves to PAID state if all payments are repaid.
- Emits a
PaymentsRepaid
event with the range of repaid payments.*
_debitCollateral
*Disposes the collateral from payments. Burns the collateral ifcollateralReceiver
is the zero address.
Requirements:
- Each payment collateral MUST be owned by this contract.
- The collateral is transferred to the collateralReceiver if provided, otherwise it is burned.*