ERC-8348 - Financial Lease

Created 2026-07-23
Status Draft
Category ERC
Type Standards Track
Authors
Requires

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", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Definitions

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:

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");

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);
}

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);

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);
}

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

Copyright

Copyright and related rights waived via CC0.