Abstract
This EIP defines a standard interface for financial lease agreements (finance leases) represented on-chain. Each lease is identified by a leaseId and the lessor position is represented as an ERC-721 token, making assignment and securitization of lease portfolios compatible with existing NFT infrastructure. The interface exposes the payment schedule, outstanding balance, arrears and default state, purchase option, and party assignment, while remaining neutral with respect to jurisdiction, interest mathematics, and compliance regime.
Schedules are denominated in abstract units of account with an explicit conversion to the payment asset, so that both fixed-amount leases and index-adjusted leases (UVA in Argentina, UF in Chile, IPCA-linked in Brazil) implement the same interface.
An optional extension binds the lease to an on-chain token representing the leased asset, enabling atomic settlement of the purchase option.
Motivation
Financial leasing is a major credit instrument worldwide, yet no ERC defines how a lease contract should be queried or observed on-chain. ERC-4907 standardizes temporary usage rights for NFTs but does not model installments, interest, arrears, purchase options, or assignment. ERC-2615 (a stagnant Draft) adds rental and mortgage roles and liens to ERC-721 but has no credit semantics: no schedules, no indexed denominations, no delinquency model, no purchase option. ERC-3475 standardizes fungible debt securities organized in classes and nonces, oriented to redemption, not bilateral contracts with named parties, formal default, or asset escrow. Outside the EVM standards process, ACTUS (Algorithmic Contract Types Unified Standards) defines a taxonomy of roughly three dozen contract types describing financial instruments as algorithmic cash-flow patterns, and has been used as a reference standard by the US Office of Financial Research. A Solidity encoding existed but covered a single contract type and has been unmaintained since 2020. ACTUS and this standard address different problems: ACTUS is a modelling ontology that requires adopting its full taxonomy to describe an instrument, while this standard defines how a lease contract is observed and queried without prescribing how its obligations are computed. An implementation MAY use an ACTUS engine internally and expose this interface externally. Compliance standards such as ERC-3643 and ERC-7943 govern who may hold a token, but not the financial semantics of a lease.
Without a common interface, every originator exposes bespoke contracts, and integrators (secondary marketplaces, securitization vaults, auditors, credit scorers) must write custom adapters per originator and per country. This standard follows the approach of ERC-4626: it does not invent leasing; it defines a common way to interact with lease contracts, so that a fund can price and acquire lease portfolios originated in different countries through one interface.
The semantics of "financial lease" used here follow the UNIDROIT Convention on International Financial Leasing (Ottawa, 1988): a lessor grants a lessee the use of an asset against periodic payments, with an eventual option to purchase. Terminology is aligned with IFRS 16 where applicable.
Specification
The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY" in this document are to be interpreted as described in RFC 2119.
Definitions
- Unit of account: the abstract denomination of the schedule (e.g. UVA, UF, or the payment asset itself for fixed leases).
- Payment asset: the ERC-20 token in which payments are made.
- Lessor position: ownership of the lease receivable, represented by the ERC-721 token whose
tokenIdequalsleaseId.
Core interface
Implementations MUST implement ERC-165 and ERC-721, and MUST use tokenId == leaseId. Transferring the ERC-721 token assigns the lessor position; implementations MAY restrict transfers through a compliance layer.
interface IFinancialLease {
enum LeaseStatus {
Active, InArrears, InDefault,
Terminated, Completed, PurchaseExercised
}
// Legal layer
function jurisdiction(uint256 leaseId) external view returns (bytes2);
function governingLaw(uint256 leaseId) external view returns (string memory);
function agreementHash(uint256 leaseId) external view returns (bytes32);
function assetReference(uint256 leaseId) external view returns (string memory);
// Parties
function lessor(uint256 leaseId) external view returns (address);
function lessee(uint256 leaseId) external view returns (address);
// Denomination and conversion
function paymentAsset(uint256 leaseId) external view returns (address);
function denomination(uint256 leaseId)
external view returns (string memory symbol, address oracle);
function convertToAssets(uint256 leaseId, uint256 units)
external view returns (uint256 assets);
function convertToUnits(uint256 leaseId, uint256 assets)
external view returns (uint256 units);
function conversionRateAsOf(uint256 leaseId)
external view returns (uint256 rate, uint64 asOf);
// Schedule (immutable, in units)
function paymentCount(uint256 leaseId) external view returns (uint256);
function paymentAt(uint256 leaseId, uint256 index)
external view returns (uint256 units, uint64 dueDate, bool paid);
// Live economics
function outstandingUnits(uint256 leaseId) external view returns (uint256);
function outstandingBalance(uint256 leaseId) external view returns (uint256);
function nextPayment(uint256 leaseId)
external view returns (uint256 assets, uint64 dueDate);
function arrears(uint256 leaseId) external view returns (uint256);
function status(uint256 leaseId) external view returns (LeaseStatus);
// Actions
function pay(uint256 leaseId, uint256 assets) external;
function purchaseOption(uint256 leaseId)
external view returns (uint256 priceInAssets, bool exercisable);
function exercisePurchaseOption(uint256 leaseId) external;
// Events
event LeaseCreated(uint256 indexed leaseId, address indexed lessor,
address indexed lessee, bytes2 jurisdiction, address paymentAsset);
event PaymentReceived(uint256 indexed leaseId, address indexed payer,
uint256 assets, uint256 unitsSettled, uint256 conversionRate,
uint256 newOutstandingUnits);
event ArrearsAccrued(uint256 indexed leaseId, uint256 totalArrearsUnits);
event DefaultDeclared(uint256 indexed leaseId, address indexed declarer);
event DefaultCured(uint256 indexed leaseId);
event PurchaseOptionExercised(uint256 indexed leaseId, uint256 priceInAssets);
event LeaseTerminated(uint256 indexed leaseId, LeaseStatus finalStatus);
event LesseeAssigned(uint256 indexed leaseId,
address indexed oldLessee, address indexed newLessee);
}Normative requirements:
- The schedule returned by
paymentAtMUST be immutable afterLeaseCreated, and MUST be denominated in units of account. - For fixed-denomination leases,
denominationMUST returnoracle == address(0)and both conversion functions MUST be the identity function. outstandingBalance(id)MUST equalconvertToAssets(id, outstandingUnits(id)).- The conversion rate returned by
conversionRateAsOfMUST express how many base units of the payment asset correspond to1e18units of account, absorbing both the oracle's and the payment asset's decimal conventions. - Rounding MUST NOT favor the caller:
convertToAssetsused to compute amounts owed MUST round up;convertToUnitsused to credit payments MUST round down. Implementations MUST document rounding. - Arrears and penalties MUST accrue in units of account. Penalty accrual MUST NOT reduce or be conflated with schedule principal.
- The arrears and penalty amounts reported by
arrears(leaseId)MUST be a function of the payment schedule, the recorded payment history, and the time elapsed since each installment's due date. They MUST NOT depend on the number, frequency, or timing of the transactions that caused accrual state to be persisted. Two leases with an identical schedule, identical payments and identical elapsed time MUST report identical arrears, however many state-mutating calls occurred in between. - Penalty accrual for an installment MUST be measured from that installment's own due date. An implementation MUST NOT grant an implicit grace period by starting accrual at the moment delinquency is first observed on-chain.
paymentAtMUST report an installment as paid only when it has been effectively settled; overdue unpaid installments MUST NOT be reported as paid.- View functions MUST report state accrued as of the querying
block.timestamp, regardless of when the implementation last persisted state. An implementation MAY accrue lazily in state-changing calls, but a caller that only reads MUST NOT observe stale delinquency, arrears, or status. - An installment falls due when
block.timestampexceeds itsdueDate. Payment at exactlydueDateMUST NOT be treated as overdue. PaymentReceived.conversionRateMUST record the rate applied, using the same scaling asconversionRateAsOf, so historical conversions are reconstructible without oracle history.- Transitions to
InArrearsMUST be objective (a due date elapsed unpaid). Transitions toInDefaultMUST be explicit acts by an authorized declarer and MUST emitDefaultDeclared. ArrearsAccruedsignals the objective fact that a due date elapsed unpaid. It does not by itself imply economic loss: an installment settled shortly after its due date may emit the event with no penalty accrued. Consumers evaluating credit behaviour SHOULD read the reported amount rather than the mere occurrence of the event.- Lessee assignment MUST emit
LesseeAssigned. It MUST be authorized either by the outgoing lessee, or by a role explicitly and separately granted that authority. Holding a role whose purpose is default declaration, servicing, or holding the lessor position MUST NOT by itself confer authority to reassign the lessee, and an implementation MUST NOT default such authority to the lease originator. - A role tied to the lessor position — including default-declaration authority — SHOULD resolve to the current holder of the ERC-721 token rather than to a fixed address recorded at origination, so that it follows the economic position when the lease is assigned.
- If a required oracle is stale beyond the implementation's documented tolerance, state-changing functions that depend on conversion SHOULD revert;
conversionRateAsOfMUST always expose the timestamp of the rate that would be applied. - The statuses
Completed,PurchaseExercisedandTerminatedare terminal. An implementation MUST NOT transition a lease out of a terminal status, and MUST determine terminality by explicit status membership rather than by the ordering of enumeration members. - Default is curable: a lease in
InDefaultwhose arrears are settled MUST return to a non-delinquent status and MUST emitDefaultCured. This preserves the standard's separation between the objective fact of delinquency (InArrears) and the formal act of declaring default (InDefault), and givesDefaultCuredoperational meaning. INPUT_COLLECTIONSandINPUT_ARREARS_RECORDreport the state of the collections process — notices sent, payment plans agreed, referral to legal. They MUST NOT be read as an authoritative restatement of the amount returned byarrears(), which remains the sole on-chain source of truth for amounts owed.INPUT_INSURANCE_STATUSis scoped to insurance covering the leased asset itself, not to instruments guaranteeing payment.
Lease lifecycle
A lease is originated in Active and reaches exactly one terminal status.
| From | To | Trigger |
|---|---|---|
Active | InArrears | a due date elapses unpaid |
InArrears | Active | arrears settled |
Active / InArrears | InDefault | formal declaration by an authorized declarer |
InDefault | Active / InArrears | arrears settled (DefaultCured) |
Active / InArrears / InDefault | Terminated | early termination |
| any non-terminal | Completed | full schedule settled |
Completed | PurchaseExercised | purchase option exercised |
Permitted operations by status:
| Operation | Active | InArrears | InDefault | Terminal |
|---|---|---|---|---|
pay | ✓ | ✓ | ✓ | ✗ |
declareDefault | ✓ | ✓ | ✗ | ✗ |
| lessee reassignment | ✓ | ✓ | ✓ | ✗ |
| propose / accept termination | ✓ | ✓ | ✓ | ✗ |
| terminate for default | ✗ | ✗ | ✓ | ✗ |
exercisePurchaseOption | ✗ | ✗ | ✗ | only from Completed |
updateServicing | ✓ | ✓ | ✓ | ✓ |
updateServicing remains available on terminated leases because servicing attestations report observed facts and do not alter lease state.
Whether lessee reassignment is permitted while a lease is InDefault is a commercial policy rather than an interoperability concern. Implementations MAY permit or forbid it, and SHOULD document which they do.
Early termination
A lease MAY terminate before its schedule completes. The standard defines when a lease may reach Terminated and requires the reason to be observable; it does not define how any remaining obligation is settled.
Termination reasons are domain-separated identifiers:
bytes32 constant TERMINATION_MUTUAL_AGREEMENT = keccak256("erc8348.termination.mutualAgreement");
bytes32 constant TERMINATION_DEFAULT = keccak256("erc8348.termination.default");- Termination by mutual agreement MUST require affirmative action from both the lessee and the holder of the lessor position — a propose/accept sequence or an equivalent mechanism. It MAY be initiated from any non-terminal status.
- Termination for default MUST require the lease to be in
InDefaultand MUST NOT take effect before a configurable delay has elapsed since the declaration. That delay MUST be greater than zero: a zero value admits several reasonable readings and MUST be rejected at origination rather than assigned a default meaning. LeaseTerminatedMUST report the reason. Implementations MAY define additional reasons under their own domain without changing this interface.- Economic quantities reported for a terminated lease — outstanding balance, arrears, penalties — MUST NOT change after termination. The standard does not prescribe how an implementation achieves this.
- This specification deliberately leaves post-termination settlement out of scope: what is owed after early termination depends on the agreement, the jurisdiction and the product, and normalizing it would impose commercial policy rather than define an interface. Consequently no state-changing payment operation is defined once a lease is terminal, and implementations requiring on-chain settlement SHOULD define it as an extension with its own semantics.
Optional extension: anchored leases
Where a lease is written over a titled asset recorded in an ERC-8325 registry, implementations MAY expose the binding explicitly rather than encoding it in the assetReference string. This avoids cross-registry ambiguity: an anchor identifier alone is insufficient without the registry it lives in and the chain that registry is deployed on.
interface IFinancialLeaseAnchored {
/// @return chainId EIP-155 chain ID of the registry
/// @return registry ERC-8325 registry address
/// @return anchorId anchor identifier within that registry
function assetAnchor(uint256 leaseId) external view returns (
uint256 chainId, address registry, bytes32 anchorId);
}- A lease MAY be unanchored, in which case
assetAnchorreturns zero values. - The tuple MUST be all-zero or fully populated. A partially zeroed tuple — a nonzero
anchorIdwith a zero registry, for instance — MUST be invalid, since it leaves consumers to define their own handling of an ambiguous reference. leaseIdremains the lease layer's own identifier; this extension expresses a relationship to the asset layer, it does not replace the lease identifier with the anchor identifier. The two objects have distinct lifecycles.- Implementations of this extension MUST return true from
supportsInterfacefor0x09fce36a.
Input freshness
A lease depends on inputs with independent freshness characteristics. The reference-index observation used to convert an indexed schedule has one timestamp; off-chain servicing data (reconciled collections, manually recorded arrears, insurance status, asset condition, residual-value appraisals) has others. A consumer composing a lease-portfolio NAV cannot treat a freshly published NAV as fresh if it incorporates an economically old input.
Implementations MAY expose per-input freshness through a single parameterized view. This interface reports; it does not enforce. A consumer decides what staleness is acceptable for its purpose.
/// Base input identifiers, domain-separated. Implementations MAY define
/// additional identifiers under their own domain.
bytes32 constant INPUT_INDEX_OBSERVATION = keccak256("erc8348.input.indexObservation");
bytes32 constant INPUT_COLLECTIONS = keccak256("erc8348.input.collections");
bytes32 constant INPUT_ARREARS_RECORD = keccak256("erc8348.input.arrearsRecord");
bytes32 constant INPUT_INSURANCE_STATUS = keccak256("erc8348.input.insuranceStatus");
bytes32 constant INPUT_ASSET_CONDITION = keccak256("erc8348.input.assetCondition");
bytes32 constant INPUT_RESIDUAL_APPRAISAL = keccak256("erc8348.input.residualAppraisal");
/// @return observedAt when the datum was observed off-chain
/// @return reportedAt when it was recorded on-chain
/// @return maxStaleness issuer-declared tolerance (0 = none declared)
function inputFreshness(uint256 leaseId, bytes32 input)
external view returns (uint64 observedAt, uint64 reportedAt, uint64 maxStaleness);- Implementations MUST expose both timestamps. Observation time is what a valuation consumer needs to judge how economically old an input is; report time is what accountability needs to know when the chain learned of it. Reporting only one loses information the other layer may require.
INPUT_INDEX_OBSERVATIONis not a stored attestation: its timestamps MUST be derived fromconversionRateAsOf, and itsmaxStalenessreflects the oracle tolerance already governing conversion. It is the only input whose staleness MAY revert a state-changing call (pay), because conversion requires it.- The remaining inputs are attestations maintained off-chain and surfaced on-chain by an authorized servicer. Updating them MUST NOT affect lease state: outstanding balance, status, and arrears are computed independently of servicing freshness. Servicing staleness is observable, never enforced.
- An implementation MUST reject an
observedAtin the future. It MUST NOT reject an old one: how old is too old is the consumer's judgement, not the standard's. maxStalenessMUST be set as lease configuration, not by the servicer supplying the attestation. A servicer declaring the tolerance applied to its own attestations is self-assessment.- Querying an input that has never been attested MUST return zero values rather than reverting: never reported is itself information.
- Input identifiers are domain-separated
bytes32values rather than a closed enumeration, so that lease structures with inputs beyond the base set extend without an interface change. The base identifiers above MUST be declared in the interface so the common set does not fragment across implementations.
Optional extension: asset-bound leases
Contracts implementing this extension MUST hold the bound asset token in escrow while status is Active, InArrears or InDefault.
interface IFinancialLeaseAssetBound {
enum AssetStandard { ERC721, ERC1155, ERC20 }
function boundAsset(uint256 leaseId) external view returns (
address token, uint256 tokenId, uint256 amount, AssetStandard std);
function canSettleAsset(uint256 leaseId, address to)
external view returns (bool);
event AssetEscrowed(uint256 indexed leaseId, address token, uint256 tokenId);
event AssetSettled(uint256 indexed leaseId, address indexed to);
event AssetReleased(uint256 indexed leaseId, address indexed to);
}- On
exercisePurchaseOption, ifcanSettleAsset(id, lessee)is true, settlement MUST be atomic with payment. If false, the option exercise MUST still be recorded and the asset MUST remain claimable by the lessee once the underlying token's transfer restrictions allow it. - Release of the asset to the lessor upon default MUST NOT be an automatic consequence of
InDefault. It MUST require an explicit call by an authorized role and SHOULD be subject to a configurable timelock, reflecting jurisdictional repossession requirements. - If the bound asset implements ERC-4907, the implementation SHOULD set the lessee as
userfor the duration of the lease.
Interface identifiers
The ERC-165 identifiers for this standard are:
| Interface | Identifier |
|---|---|
IFinancialLease | 0xe3e0ac48 |
IFinancialLeaseAssetBound | 0xf71550a8 |
IFinancialLeaseAnchored | 0x09fce36a |
Each identifier is the XOR of the function selectors declared in that interface alone; inherited and extension functions are not included. An implementation MUST return true from supportsInterface for 0xe3e0ac48, and MUST return true for the identifier of each optional extension it implements.
Rationale
Units of account follow the ERC-4626 share/asset separation: indexed leases are first-class citizens rather than a special case, which is essential in the jurisdictions where leasing volume is concentrated in Latin America. A fixed-rate lease is the degenerate case with identity conversion.
Lessor-position-as-NFT makes portfolio assignment and securitization free: existing ERC-721 marketplaces, custody and vault tooling work unchanged, with compliance enforced in the transfer hook rather than in this interface.
Two-tier delinquency (InArrears vs InDefault) separates the objectively computable fact of a missed payment from the legally significant declaration of default, which in many jurisdictions requires notice or grace periods. The standard records both without opining on local law.
Payment imputation is unspecified (penalties vs interest vs principal) because ordering rules differ by jurisdiction and are sometimes mandatory law. PaymentReceived exposes enough data for indexers to reconstruct any imputation.
Observation rather than modelling. A complete taxonomy of financial instruments — the approach taken by ACTUS — describes what a contract is with enough fidelity to compute its cash flows from first principles. That fidelity has a cost: an integrator must adopt the taxonomy to read anything. This standard takes the opposite trade: it says nothing about how obligations are computed and only defines how the result is observed, so that a marketplace or credit scorer can read a lease without adopting a modelling framework.
Accrual is defined by elapsed time, not by transaction history. An implementation that accrues penalties by repeatedly applying a periodic rate to a running balance produces different totals depending on how often the contract happens to be touched — and since payment entry points are typically permissionless, the party that benefits from a higher figure can also produce it at no cost. Requiring the reported figure to be a function of the schedule and elapsed time removes that possibility without prescribing whether interest is simple or compound.
Authority over the lessee position is separated from other roles. A role granted for one purpose — declaring default, servicing a portfolio, holding the lessor position — does not thereby acquire authority over who receives the purchase option. Conflating them creates a conflict of interest whenever the role holder benefits from a reassignment, and the party best positioned to exploit it is often the one the role defaults to.
Backwards Compatibility
The standard composes with, and does not modify, ERC-20, ERC-721, ERC-165 and ERC-4907.
Security Considerations
- Oracle manipulation and staleness: conversion oracles are the main attack surface for indexed leases. Implementations MUST document their oracle source, update cadence and staleness policy, and SHOULD revert state changes on stale data.
- Rounding: directional rounding rules above prevent dust-extraction attacks analogous to ERC-4626 inflation attacks.
- Penalty conflation: implementations that mix penalty stock with schedule principal in a single accumulator risk crediting penalty payments against principal. Penalties MUST be tracked separately.
- Compliance-gated settlement:
exercisePurchaseOptionmay be unable to deliver a compliance-restricted asset; recording the exercise while deferring delivery prevents loss of an acquired right. - Repossession: the escrow mechanism makes repossession technically trivial; the timelock and role requirements exist so that on-chain capability does not outrun legal authority.
- Legal enforceability:
agreementHashbinds the on-chain state to an off-chain agreement, but enforceability of the token as title or receivable depends on each jurisdiction's legal wrapper. This standard makes jurisdiction observable; it does not create legal effect. - Servicing attestations:
inputFreshnessfor off-chain categories reflects what an authorized servicer has attested, not independently verified truth. A stale or dishonest servicer degrades the freshness signal but cannot alter lease state, since servicing data is isolated from balance and status computation. Consumers relying on servicing freshness SHOULD treat the servicer as a trusted party and weight the signal accordingly. - Frequency-dependent accrual: an implementation whose arrears figure depends on how often accrual state was persisted can be manipulated by any party able to call the contract, including the lessor at no net cost. Conformance suites SHOULD include a differential test comparing a single end-of-period accrual against repeated intermediate accruals over the same elapsed time.
- Role conflation: implementations SHOULD treat authority to change who receives the purchase option as access-control critical. Conformance suites SHOULD assert that no address other than the current lessee can change the lessee of record without an explicitly and separately granted authority.
Copyright
Copyright and related rights waived via CC0.
