How it works
The five steps, end to end.
Five steps. Only one of them is new to you, and it is free.
The five steps
1. Approve a token, exactly as you always do
You use an app. It asks for an approval. You grant it. This happens entirely outside DORT and DORT never sees it.
you -> token.approve(theApp, 1000)Nothing about this step changes. DORT is not in the path, and it does not need to be.
2. Sign one message choosing when it should end
Now you sign an EIP 2612 permit on that same token. The message says, in effect, set my allowance to this spender back to zero.
Permit {
owner: you
spender: theApp
value: 0 <- always zero
nonce: <the token's current nonce for you>
deadline: <far in the future>
}This is a signature, not a transaction. It costs nothing, it touches no chain, and it does not take effect until somebody submits it.
3. Confirm once to start the clock
You call scheduleExpiry on the registry, handing it the signature, the time you want the
approval to end, and a small amount of ETH as a bounty.
you -> registry.scheduleExpiry(token, theApp, expiresAt, permitDeadline, v, r, s) + bountyOne transaction. From here the clock runs without you.
4. Nothing happens, on purpose
Between now and expiresAt, the approval works normally. DORT holds the signature and the
bounty, and does nothing else. Your allowance is untouched.
5. The approval removes itself
Once block.timestamp reaches expiresAt, anyone at all can call execute. The registry
replays your stored signature at the token, the allowance goes to zero, and whoever made the call
collects the bounty.
anyone -> registry.execute(jobId)
-> token.permit(you, theApp, 0, deadline, v, r, s)
-> allowance is now zero
-> bounty goes to the callerYou did not have to be online. You did not have to remember.
Why a bounty
Because "automatically" has to mean something, and on a blockchain nothing runs by itself. Somebody has to pay gas to send that transaction.
The bounty is what makes it worth their while. It is a public reward for a public service: whoever performs the revocation gets paid for it. There is no privileged keeper, no allow list, and no relationship to maintain. You can run it yourself if you like.
Read Keepers and bounties for how to size one, and what happens if you size it too low.
What if you change your mind
Call cancel. Only you can, and it works any time before the job runs.
you -> registry.cancel(jobId)
-> the job is marked cancelled
-> your bounty comes straight backCancelling does not touch the approval itself. It only calls off the scheduled expiry.
What if something goes wrong
There is exactly one escape hatch and it covers every case: cancel and take your bounty back.
That applies whether the token turned out not to support the right kind of permit, whether somebody replayed your signature early, or whether you simply changed your mind. Your ETH is never stuck anywhere you cannot reach it, and the protocol never held your tokens to begin with.
Job lifecycle sets out every state a job can be in and how it got there.
What DORT never does
- It never moves your tokens. It does not call
transferortransferFromand holds no token balances. - It never increases an allowance.
executehardcodes a value of zero. - It never needs a server. Any public RPC endpoint is enough to read the state and run a job.