An intent is a signed message expressing willingness to borrow or lend under specific conditions. Unlike pool deposits that commit capital immediately, intents commit only to terms. Your assets stay in your wallet until a counterparty agrees.
Anatomy of an intent
Borrow intent
A borrow intent specifies what you want to borrow and what you offer as collateral:
interfaceBorrowIntent{ // What you offer as collateralcollaterals:Array<{chainId:number// Chain where collateral resides (1=Ethereum, 42161=Arbitrum, etc.)contractAddress:string// Token contract addressamount:string// Amount in wei (18 decimals)}> // What tokens you accept as loan principalacceptedPrincipals:Array<{chainId:numbercontractAddress:string}> // Loan termsminLoanAmountUsd:string// Minimum loan size (prevents dust matches)minLtvBps:number// Minimum LTV in basis points (7500 = 75%)maxAprBps:number// Maximum APR in basis points (700 = 7%)loanLifetime:number// Duration in seconds // Where to receive fundspayoutAddress:string // Cryptographic commitmentsignatureProof:{message:string// EIP-712 typed data messagesignature:string// ECDSA signature}}
Lend intent
A lend intent specifies what you offer to lend and what collateral you accept:
Both intents include a cryptographic signature binding you to these terms. The signature uses EIP-712 typed data for security and wallet compatibility.
How matching works
The matching engine continuously scans for compatible intent pairs. The matching algorithm validates five conditions:
How matching works
Collateral asset - The borrower offers collateral that appears on the lender's accepted list.
Principal asset - The lender offers principal that appears on the borrower's accepted list.
LTV overlaps - The borrower's minimum is at or below the lender's maximum. If a borrower wants at least 75% LTV and a lender allows up to 80%, any value between 75-80% works.
APR overlaps - The borrower's maximum meets or exceeds the lender's minimum. If a borrower accepts up to 8% and a lender requires at least 6%, any rate between 6-8% works.
Loan amount - The effective principal meets both parties' minimum loan size requirements.
When all conditions are satisfied, the engine computes effective terms and creates a match:
Term computation
For overlapping ranges, the protocol selects the lender's terms:
LTV: Uses the lender's maximum LTV. This protects the lender - they set the upper bound of risk they accept. Borrowers who wanted higher LTV still benefit because the lender's max is within their acceptable range.
APR: Uses the lender's minimum APR. Lenders get their required rate. Borrowers benefit because it's the lowest rate within the overlap.
Both parties know exact terms before committing.
Multi-order generation
A single intent can generate multiple orders. If a borrower offers three collateral types and accepts two principal types, the protocol generates six orders - one for each combination.
This enables efficient matching. A large lender intent might fill multiple borrower orders. A borrower might receive principal from multiple lenders. The matching engine optimizes for maximum capital deployment while respecting each party's constraints.
Order states
Each order tracks its own fill state:
Status
Meaning
OPEN
Available for matching
PARTIALLY_FILLED
Some matched, remainder available
FILLED
Completely matched
CANCELLED
User cancelled before matching
Partial fills allow large intents to match incrementally. A lender offering $100,000 might fill five $20,000 borrower orders, each creating a separate loan with independent terms.
Loan lifecycle
Once matched, a loan progresses through defined stages:
Loan statuses
Status
Description
PENDING_TRANSFER
Match found, waiting for on-chain execution from both parties
ACTIVE
Funds settled, loan running, interest accruing
REPAID
Borrower repaid in full, loan closed successfully
LIQUIDATED
Collateral value dropped, position was liquidated
DEFAULTED
Loan expired without repayment
FAILED
On-chain execution failed or timed out
Cancellation
You can cancel unmatched orders at any time. Once an order matches, that specific match cannot be cancelled - the loan process has begun.
For intents that generated multiple orders, you can cancel only the unfilled ones. Matched orders proceed to execution regardless.
interface LendIntent {
// What you offer to lend
principals: Array<{
chainId: number
contractAddress: string
amount: string // Amount you're willing to lend
}>
// What collateral you accept
acceptedCollaterals: Array<{
chainId: number
contractAddress: string
}>
// Loan terms
minLoanAmountUsd: string // Minimum loan size
maxLtvBps: number // Maximum LTV you'll extend (8000 = 80%)
minAprBps: number // Minimum APR you require (500 = 5%)
loanLifetime: number // Duration in seconds
// Cryptographic commitment
signatureProof: {
message: string
signature: string
}
}
interface MatchResult {
lendOrderId: number
borrowOrderId: number
// Assets being exchanged
principalAsset: {
chainId: number
contractAddress: string
}
collateralAsset: {
chainId: number
contractAddress: string
}
// Computed amounts
effectivePrincipalAmount: bigint // Wei (18 decimals)
effectiveCollateralAmount: bigint // Wei (18 decimals)
// Negotiated terms
effectiveLtvBps: number // Final LTV in basis points
effectiveAprBps: number // Final APR in basis points
// Which side is fully consumed
exhausted: "LENDER" | "BORROWER"
}