ERC-8348: Financial Lease

Hi all,

We’ve been building tokenized financial leases and kept running into the same problem: there’s no standard way to expose a lease contract on-chain, so every integration is a custom adapter. We drafted an ERC for it and want to sanity-check the design here before opening the PR to ethereum/ERCs.

Quick scope note: by “financial lease” we mean the credit instrument (lessor funds an asset, lessee pays installments, usually with a purchase option at the end) — not NFT rentals. ERC-4907 handles temporary usage rights well, but it has no notion of installments, arrears, purchase options, or assignment. Compliance standards like ERC-3643 and ERC-7943 decide who can hold a token, not what a lease is. And the recent titled-asset family (ERC-8325..8330) covers the asset layer — binding, documents, compliance logs, NAV — but not the credit contract written on top of it. That contract layer is what we’re proposing to standardize.

The approach steals liberally from ERC-4626: don’t invent the instrument, standardize how to query and observe it. Semantics follow the UNIDROIT Convention on International Financial Leasing (1988) and IFRS 16 terminology, which keeps the interface jurisdiction-neutral without us having to argue about any particular country’s law.

The main design decisions, and why:

Lessor position as ERC-721, tokenId == leaseId. Assigning a lease or securitizing a portfolio becomes an NFT transfer, so existing marketplace/custody/vault tooling works with zero changes. Compliance hooks belong in the transfer path, not in this interface.

Schedules in units of account, not payment tokens. This one matters a lot in practice. In several of the largest leasing markets, contracts are inflation-indexed (UVA in Argentina, UF in Chile, IPCA-linked in Brazil), so a schedule of fixed token amounts is simply wrong there. In our design the schedule is immutable in abstract units, and convertToAssets / convertToUnits resolve to the ERC-20 payment asset at query time through a per-lease oracle. A fixed-rate lease is just the degenerate case: identity conversion, oracle == address(0). Rounding direction is normative (charge up, credit down — we all remember the 4626 inflation attacks), and every PaymentReceived event records the conversion rate applied, so historical payments can be audited without needing oracle history.

Two delinquency tiers. InArrears is objective: a due date passed unpaid, computable on-chain. InDefault is a formal act by an authorized declarer, because plenty of jurisdictions require notice or grace periods before default has legal effect. The standard records both and takes no position on local law.

There’s also an optional extension (IFinancialLeaseAssetBound) for when the leased asset itself is tokenized: the lease contract escrows the asset token, exercisePurchaseOption() settles atomically, and repossession on default is deliberately not automatic — it needs an authorized call plus a configurable timelock, so on-chain capability doesn’t outrun legal authority. If the asset implements ERC-4907, the lessee gets set as user for the duration. And if the asset is a titled asset, assetReference MAY be an ERC-8325 anchorId and agreementHash MAY commit to an ERC-8326 document bundle instead of a single document.

Abridged core interface:

interface IFinancialLease {
    function jurisdiction(uint256 leaseId) external view returns (bytes2);
    function agreementHash(uint256 leaseId) external view returns (bytes32);
    function denomination(uint256 leaseId) external view returns (string memory symbol, address oracle);
    function convertToAssets(uint256 leaseId, uint256 units) external view returns (uint256);
    function paymentAt(uint256 leaseId, uint256 i) external view returns (uint256 units, uint64 dueDate, bool paid);
    function outstandingUnits(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);
    function pay(uint256 leaseId, uint256 assets) external;
    function exercisePurchaseOption(uint256 leaseId) external;
    // + events: LeaseCreated, PaymentReceived, DefaultDeclared, ...
}

Full draft and a reference implementation (Foundry tests, mock index oracle) are written; we’ll link the PR in this thread once it’s open.

Things we’re genuinely unsure about and would like input on:

  1. Payment imputation. We left the ordering of penalties/interest/principal unspecified on purpose — in some jurisdictions it’s mandatory law, so baking one order into the standard would break compliance somewhere. pay() emits enough data to reconstruct any imputation off-chain. Is that acceptable under-specification, or would you add an optional view exposing the implementation’s ordering?

  2. Oracle staleness. We require staleness to be observable (conversionRateAsOf) and documented, but don’t mandate a policy. We’re considering adopting ERC-8330’s split between publication staleness and valuation staleness for index oracles. Should the standard go further than observability?

  3. Lessee as a position. The lessor side is an NFT; the lessee is just an address with an assignment function. Tokenizing the lessee position too would enable lease-to-own secondary markets, but it doubles the compliance surface. Worth it in v1, or scope creep?

  4. Prior art. We reviewed ERC-4907, ERC-2615, ERC-3475, ERC-3525, ERC-4626, ERC-3643, ERC-7943 and the titled-asset family (ERC-8325..8330). Closest matches: ERC-2615 (stagnant Draft from 2020) adds rental/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 (classes/nonces, redemption-focused), not bilateral contracts with named parties, formal default, or asset escrow. The titled-asset family standardizes the asset layer, not the contract layer — if anything we see composition there (lease default events as ERC-8328 entries, portfolio NAV via ERC-8330). The 2022 “Financial Primitive Standard” thread proposed generalized token accounting and never became an ERC. What are we missing?

  5. Composition with the titled-asset layer. Should subject identifiers (leaseId vs ERC-8325 anchorId) be alignable by convention? And is a lease-portfolio NAV profile for ERC-8330 worth specifying?

Happy to be told any of this is wrong … that’s what the thread is for.

PR is now open: Add ERC: Financial Lease by javierpmateos · Pull Request #1907 · ethereum/ERCs · GitHub (ERC-8348)

The reference implementation is included under assets/ … Foundry suite with 8 passing tests, including regression tests for two bugs we caught in internal review (schedule state misreporting overdue installments as paid, and penalty payments incorrectly reducing principal) and a fuzz
test over the directional rounding invariant. Feedback on either the spec or the implementation is welcome, here or on the PR.