Intentional brings factoring, trade finance's oldest instrument, to withdrawal queues.
Intentional is onchain factoring for delayed withdrawal claims.
When you exit Lido, your stETH becomes an unstETH NFT that pays out days later — roughly 2 days at the median and 13 days at the 90th percentile. That claim is real value you cannot use. It is not an ERC-20, so no AMM, DEX aggregator or lending market can price or route it. Your options are to wait, or to dump the underlying at a spot discount.
Intentional is a market for those claims. A liquidity provider — the "factor" — buys your future payout and pays you now. You get cash today; they take the wait. It is the oldest instrument in trade finance, applied to withdrawal queues.
The settlement kernel enforces exactly one invariant: payment if and only if complete, measured claim acquisition, in the same transaction. There is no escrow, no counterparty risk window, and no partial state. One of our invariant tests is named after it — invariant_PaymentIffCompleteMeasuredAcquisition.
Two seller paths are live on Ethereum mainnet: • Originate — sell liquid stETH. The protocol opens a canonical Lido withdrawal request owned directly by the factor, and the exact WETH payment lands in your wallet atomically. • Exit — sell an unstETH NFT you already hold. The NFT moves to the buyer and payment reaches you in the same transaction.
Failure is atomic in both directions: if the claim does not fully arrive, or the payment is not exact to the wei, the entire transaction reverts — no claim created, no payment made, no nonce consumed.
Lido is the proven instance, not the design. A staking withdrawal queue, an asynchronous vault redemption, and a real-world-asset fund's T+N settlement are the same shape: a position that is near-certainly worth something, at a date the holder cannot choose, that no AMM can price because it is not fungible. Every one of them strands capital for exactly as long as the queue runs.
The kernel never mentions Lido. Claim acquisition sits behind a two-function adapter interface, and the settlement invariant is written purely in measured balance deltas, so any claim that can be transferred or re-owned atomically fits without touching the core. Three adapters already implement that interface against genuinely different mechanics — one that originates a claim from a liquid token, one that transfers an existing NFT, and one that moves the pending portion of an ERC-7540 vault request under ERC-8161. Adding a market is a new adapter plus a single allowAdapter transaction on the already-sealed live deployment: no kernel change, no migration, no redeploy.
That points at markets much larger than staking. ERC-7540 asynchronous vaults are already production infrastructure for tokenized real-world assets, where redemption windows and T+N settlement are the norm rather than the exception — and factoring receivables is the instrument that market has used for centuries. Other LST and LRT withdrawal queues (Ether.fi and similar) are the nearest adjacent step; RWA redemption queues are where the mechanism is worth the most, because the waits are longer and the holders are least able to absorb them.
The factor's capital stays productive. WETH sits in Aave's StataWETH ERC-4626 vault between fills, earning lending yield while idle, and is materialised just-in-time during settlement. Factoring demand is episodic, so idle capital that earns nothing makes the business uneconomic; this is what makes standby liquidity worth holding.
Beyond the core market, we built two things on top:
Uniswap payouts. A seller can be paid in the asset they choose rather than always in WETH. The factor still underwrites in WETH; a Uniswap Trading API route converts the exact advance and delivers the payout asset straight to the seller inside the same atomic fill. The API is load-bearing — without its route calldata there is no payout — and the seller is protected by a signed minimum enforced against their own measured balance delta, so a degraded route reverts the whole fill rather than underpaying. Proven end-to-end on a mainnet fork with live API-produced calldata, USDC as the demonstrated asset, behind a factor allowlist rather than a compiled-in constant. 1inch Aqua / SwapVM. A custom VM instruction (opcode 0x92, ReserveClamp) clamps swap output to what the maker's ERC-4626 reserve can currently deliver, letting a maker quote from yield-bearing vault inventory instead of idle tokens. Tested against production Aqua contracts on a mainnet fork.
Contracts (Solidity 0.8.30, Foundry). AsyncClaimSettlement is the kernel. It validates an EIP-712 firm quote — seller-bound, single-use nonce with a nonce floor, 15-minute maximum lifetime, factor signature via SignatureChecker so both EOA and ERC-1271 smart-account factors work — then drives two satellites.
Claim acquisition goes through a deliberately minimal adapter interface — two functions, inspect and acquire, sixteen lines total. That narrowness is the generalization mechanism: the kernel knows only that something measurable was fully acquired, never what protocol produced it. Three adapters implement it against different mechanics: LidoWithdrawalClaimAdapter originates a new Lido request owned by the factor; LidoUnstETHExitAdapter moves an existing unstETH NFT from seller to buyer without ever taking custody; ERC8161RedeemClaimAdapter handles ERC-7540 asynchronous vault redemptions, transferring the Pending portion of a request under ERC-8161 while leaving Claimable balances untouched. The adapter allowlist is onlyFactor but deliberately not seal-gated, so a fourth market — another LST queue, an RWA redemption vault — is a new adapter and one transaction against the live deployment. ERC-8161 only went Final in 2026 and has no production vaults yet, so that adapter is proven against our own mock: an early-mover bet, stated as one.
ProductiveFundingAccount holds WETH as StataWETH ERC-4626 shares and materialises exactly the quoted payment mid-settlement. If the vault cannot deliver the exact amount, settlement never starts.
Every postcondition is a measured balance delta, never a return value. Lido's withdrawal accounting does not map cleanly onto a single transfer event, and adapters are third-party code by definition, so the kernel snapshots balances before and after and re-checks the result itself — even when the funding account has already asserted it. The executor's own return value in the payout path is deliberately discarded for the same reason.
Trust boundaries are sealed, with one door left open on purpose. The factor signer, funding account and payout executor are immutable; configureSettlement is one-shot; seal() freezes core bindings. The adapter allowlist is intentionally not seal-gated, so a new market can be added — or a compromised adapter revoked — on a live deployment without redeploying anything.
Off-chain: a keyless frontend and a server-side quote desk. The factor key lives only in a hardened signing service on a VPS bound to 127.0.0.1, reachable solely through a named tunnel. Next.js proxies quote requests to it and is stateless — it stores no requests and no signatures, and fails closed with a 503 when no desk is configured. No signing key exists in the browser bundle, the repo, the logs, or Vercel. Pricing is an explicit fixed operator spread, never presented as a market or oracle price.
Critically, the browser trusts nothing it is handed. Every signed quote is independently re-verified against live chain state before it can be acted on: the deployment must be the reviewed, sealed, unpaused one; capacity must cover the exact payment; the discount must sit inside an independent browser-side ceiling; and the claim's owner, amounts and share bounds are re-read from canonical Lido. After the fill, the app measures the seller's actual WETH delta and re-reads canonical Lido ownership. No optimistic success state is ever shown.
Uniswap Trading API integration. Requests go out server-side with x-permit2-disabled: true, the executor contract as swapper and the seller as a separate recipient, and we v response against values read from the deployedexecutor, proxy target and selector included, so a quote can never be signed for a target the executor would refuse. The returned calldata is treated as opaque and is ne Two API findings worth reporting:simulateTransaction: true fails for a zero-balance contract swapper, and permitData must be omitted rather than sent as null, which surfaces as a request-validation erred rule. Both are written up in FEEDBACK.md.

