owned this note
owned this note
Published
Linked with GitHub
# Intent Addresses
**Intent addresses guarantee a specific outcome just by sending assets to that address.** In other words, they are non-custodial receiving addresses. Just as you could send assets to an exchange's (custodial) EOA receiving address to deposit into an account, you can send assets to an intent address with onchain, publicly enforced guarantees about what happens next.
## Motivation
* **Simplicity.** "Send 0.1 ETH to this address on any chain." is the simplest, most widely supported CTA in Ethereum right now. With intent addresses, this is enough to perform arbitrary actions.
* **One-click UX.** Intent addresses can support any combination of ETH transfer, ERC-20 transfer, and ERC-20 approve.
* **Compatibility with send-only systems.** There are many systems in Ethereum that let you *send* funds to a given address, but don't natively support an arbitrary contract call. Intent addresses add this capability.
* **Bridges, including CCTP.** Turn any bridge into an arbitrary cross-chain call.
* **Popular custodial apps such as Binance and Lemon.** Turn any CEX into a wallet capable of arbitrary calls.
## Examples
* **FastCCTP / Fast Bridging**
This was our orignal motivating example. CCTP is currently the best way to move USDC between rollups. It involves minimal contract risk (in particular, there are no contracts storing large amounts of bridged funds) and no new counterparty risk (your only counterparty is Circle, which is already a counterparty when holding USDC). However, it takes ~20 minutes. Intent addresses solve this, letting us bridge USDC in seconds. We developed a system called FastCCTP as follows: Alice on Arbitrum initiates CCTP to an intent address that commits to (Bob, Base, output amount). Any LP can come and complete this immediately. The FastCCTP escrow contract records which LPs have fronted which transfers. Later, once the transfer arrives, the anyone can call claim() on the intent address--this sends the funds either to the LP that fast-finished the transfer, or directly to Bob if no LP came. This means that from the moment Alice initiated the transfer, Bob is guaranteed to receive the funds: the LPs are only for speed and convenience, not trusted. The address encodes and guarantees Alice's intent. Live demo: see https://wire.daimo.com
* **Cross-Chain Checkout**
This is a generalization of FastCCTP: say you want to make an arbitrary contract call with X amount of Y token on chain Z. We can craft an intent address that ensures this outcome given just a plain transfer of sufficient amount of any token on any chain. This allows a very easy and fast crypto payments experience. Live demo: see https://pay.daimo.com
* **Deposit directly into a Polymarket trade.**
Polymarket could implement an onboarding flow where someone clicks "Buy" → one-click signup to create an embedded wallet → receiving address where you can transfer directly from any CEX or wallet to place the trade.
* **Zero-setup hidden multisig.**
Deposit to an address from Binance or Coinbase. That money can be spent by any two of (Alice, Bob, Charlie), but onchain it looks indistinguishable from an EOA until the moment the funds are spent. Even then, only the two signers have to reveal themselves, any additional authorized signers remain hidden.
## Implementation notes

* `CREATE2` intent addresses
* Commit to exact parameters: minimum output amount, destination chain, token, contract call, etc.
* CREATE2 lets us create receiving addresses that work on any chain. The common pattern work as follows:
* LP calls on non-destination chain? If block.chainid != destination chain, only thing contract allows is swap + send to bridge.
* LP calls on destination chain? If block.chainid == destination chain (or potentially, one of several destination chains), the contract ensure the desired intent is fulfilled, enforcing specific minimum inputs.
* LP claim: if the LP already fulfilled the desired intent and funds arrive later, the intent address has some mechanism to reimburse the LP. The most straightforward way to do this is to have the factory contract creating the intent addresses serve as an escrow contract.
* `SELFDESTRUCT`
* Intent addresses can be *ephemeral*. It's possible to imagine a re-usable intent address, in which case you want to simply deploy the contract. But common uses cases in checkout, bridging, and payment requests are one-time-use. In this case, the elegant implementation is for LPs to call into a factory contract that `CREATE2`-deploys code to the intent address, does an action (such as initiating a bridge on source, or claiming bridged funds on the destination chain), then deletes the code again.
* For ephemeral addresses, we reduce state growth by cleaning up after ourselves.
* This pattern looks a bit like stateless Ethereum: instead of (deploy a contract forever > use it once or twice), it's (provide code at time of use > prove it matches the address containing funds via `CREATE2` > run the code > forget it again).
* It also looks like an ancient-but-nice Bitcoin idea: P2SH / Pay to Script Hash, and extensions such as Merkelized scripts. In those cases, Alice sends money to an address, and only later at the time of spending does Bob reveal the conditions that allow him to spend it. The network only needs that code ephemerally to validate the spend transaction, it doesn't need to store the code indefinitely.
* The case for reinstating the `SELFDESTRUCT` refund
* Right now, the EVM provides a *negative* incentive for ephemeral contracts to clean up after themselves. `SELFDESTRUCT` costs gas and provides zero refund. This is a result of path dependence: the old `SELFDESTRUCT` was a bad opcode. This was mitigated first by removing the refund (to solve "gas tokens" etc) and then fixed by restricting it to same-transaction ephemeral contracts (to solve the unlimited-state-writes problem). Had we restricted it to same-transaction use from the start, there would've been no reason to remove the refund.
* We propose reinstating the `SELFDESTRUCT` refund in order to support ephemeral addresses, and in particular to support intent addresses. This is a great UX affordance, and we want to ship it in a way that respects the network and minimizes state growth.
* It feels like a bug that shipping it in a way that wantonly grows state is currently cheaper.
## Progressive UX
One advantage of intent addresses is progressive rollout. We have deep backwards compatibility, plus a high "skill ceiling" for future UX.
For example, imagine an intent address that represents a recurring subscription. In order from worst to best:
- **User only has Binance/CB/Lemon/etc.** They send a fixed sum (say, minimum 6mo worth) to the address, from which the recipient will automatically receive the monthly amount. CEX transfer > "✅ subscribed".
- This pattern extends to even longer-tail options such as subscribing via USDT on Tron via a bridge, or directly from an onramp.
- **User has a legacy wallet like Metamask.** They're prompted to "approve (uint max) DAI". Single ugly approve > "✅ subscribed", this time with automatic renewal until cancelled.
- **User has a future wallet with support for ERC-(TBD) subscription intent addresses.** The wallet recognizes that the `approve()` destination address comes from the relevant factory. They get a beautiful and descriptive prompt, "Subscribe to polynya.eth for $14 DAI /mo?" > "✅ subscribed", automatic renewal, easy way to see all subs in one place, cancel, etc.
So we have a single onchain mechanism that supports everything from legacy CEX withdrawals to a goal-state UX competive with Apple Pay or Paypal, but permissionless.