Recipe: token permits
Goal — Get through a dapp that asks you to “approve with a signed message” when you execute through a Safe.
Good for:
- Aave v3 supply and repay flows.
- Anything that routes an approval through Permit2 (Uniswap, and the apps built on it).
- Morpho deposits that go through the bundler.
Why the signature fails
A permit is a signature over an EIP-712 message that the dapp passes on to a contract as
calldata. A Safe has no private key: it signs by recording a message hash on chain, which
ERC-1271 verifiers read back through
isValidSignature. Whether that works depends on how the verifier takes the signature,
and the answer differs by protocol.
Verifiers that take v, r, s cannot accept a Safe at all. EIP-2612’s function is
permit(address, address, uint256, uint256, uint8 v, bytes32 r, bytes32 s) — there is no
bytes parameter for a contract signature to occupy, and the implementation calls
ecrecover directly. Morpho Blue’s setAuthorizationWithSig takes the same shape. No
ERC-1271 support downstream can rescue calldata that has nowhere to put the signature.
Verifiers that take bytes generally can. Permit2 checks whether the signer has code
and routes contract signers to isValidSignature, so a Safe’s signature is valid there.
What still breaks these flows is the interface in front of them: a frontend that checks
the signature’s length, verifies it locally without ERC-1271 support, or hands it to a
backend for validation will reject a Safe’s signature before it ever reaches the chain.
Either way the rights the permit would have granted are available as a plain transaction, and every app that offers permits also offers that path.
Aave v3
Aave asks for a permit by default. Turn it off once, per browser:
- Open the Aave app and connect through Pilot.
- Open the settings menu (the gear icon, next to the wallet address).
- Switch Approve with Signed message — labelled Signed transactions in some versions — to off.
- Reload the supply or repay screen.
Aave now asks for two transactions instead of one signature: approve on the token, then
supply. Both land in the same Pilot batch and execute atomically, so the extra step
costs nothing beyond one more call in the bundle.
The toggle is stored in the browser, not in the Safe. Set it again on each browser profile you use.
Permit2
The Permit2 contract accepts a Safe’s signature, so these flows fail only when the interface in front of it does its own validation. Most of them offer an approval transaction next to the signature prompt — look for “Approve” rather than “Sign”.
If the app gives no choice, use the Add Permit2 approval transaction button in the
Pilot panel: it adds the approve(token, spender, amount, expiration) call on the Permit2
contract that the signature would have authorized.
Morpho
Deposits through the Morpho bundler ask the Safe to sign an Authorization message.
setAuthorizationWithSig recovers the signer with ecrecover, so a Safe cannot satisfy
it. The equivalent call is setAuthorization(bundler, true) on Morpho Blue, which the
panel offers directly. Authorize once and the bundler flows work from then on.
Add the approval from the panel
For every permit request it recognizes, Pilot offers the equivalent call in the panel. Adding it puts the approval in your batch, where it goes through the same policy check and the same simulation as everything else — including the allowance limits on the token, if your policy sets any.