Order Lifecycle
The lifecycle of an intent spans its initial public broadcast, potential settlement, and any necessary cancellations.
The Stages
Section titled “The Stages”| Step | Function | Who calls it? |
|---|---|---|
| Publish | announce(order, permit2Sig) |
Anyone — the owner self-submits, or a relayer broadcasts. |
| Settle | fill(order, permit2Sig, solver, routerData) |
Anyone. |
| Cancel (own gas) | cancel(order) |
The owner directly. |
| Cancel (gasless) | cancelSigned(order, deadline, ownerSig) |
Anyone broadcasts the owner’s explicit cancellation signature. |
| Cancel (backstop) | Permit2.invalidateUnorderedNonces(...) |
The owner directly on Permit2. |
Announcement
Section titled “Announcement”The announce function is the discovery feed. It is entirely optional and builds no on-chain index.
When called, it verifies the signature against the exact digest Permit2 will check. This serves as a free, pre-gas admission gate for relayers. However, a successful announcement does not guarantee the order is trustworthy or fillable:
- The signature might name a spent nonce.
- The input token might not have an active Permit2 allowance.
- An ERC-1271 smart contract wallet might change its configuration after signing.
Because of this, fillers must always dry-run the fill function to confirm the intent is executable.
announce also checks less than fill does. It rejects an order that is cancelled, expired or
carries an invalid signature — but it does not enforce startTime, and it does not look at the
Permit2 nonce or the owner’s allowance. Announcing an order before its window opens is therefore
valid and normal.
It is also not idempotent and does not consume the nonce: the same signed order can be announced
any number of times, by anyone, emitting repeated IntentAnnounced logs with the same id.
Indexers must deduplicate on id.
Nonce Semantics and State
Section titled “Nonce Semantics and State”The protocol relies on Permit2’s unordered nonces. Because Permit2 consumes the nonce during a successful pull, a second fill of the same order is structurally impossible. Therefore, the settlement contract requires no replay storage of its own.
The only persistent state the IntentSettlerV1 contract keeps is a cancelled[id] mapping, which exists strictly to support cancellation. (It also declares an EIP-1153 transient reentrancy flag, which clears at the end of every transaction and stores nothing.)
A spent nonce on Permit2 does not definitively mean an order was “filled”. The owner might have invalidated the nonce directly. Distinguishing between a fill and an invalidation requires finding a matching IntentFilled event log.
Cancellation Paths
Section titled “Cancellation Paths”Users have three paths to cancel an order:
- On-chain cancellation (
cancel): The owner pays their own gas to callcancel, recording the order hash in thecancelledmapping. - Gasless cancellation (
cancelSigned): The owner signs a cancellation message against the settler’s EIP-712 domain. A relayer broadcasts this signature to record the cancellation on-chain. - The durable backstop: The user calls
invalidateUnorderedNoncesdirectly on the Permit2 contract. This is the fallback that does not depend on the settler at all — it works even if the settler is unresponsive. Note its granularity: it clears one nonce bit in the owner’s Permit2 bitmap, so it kills every signed order that shares that owner and nonce, not oneorderHash.cancelandcancelSignedare the per-order paths.
Importantly, calling approve(Permit2, 0) on the input token is not a reliable cancellation. Re-approving the token later will immediately reactivate any unspent orders whose signatures are still valid. Nonce invalidation is the durable path, at nonce granularity.
Cancellation transactions do not automatically front-run a fill that is already in the mempool. Whichever valid transaction lands first wins the race.