Skip to main content
In short: you keep your crypto in a Safe wallet and want to know if it can use DeFiLoops. A Safe can run a batch of calls with nothing installed on it, but it needs a module installed before it can take a flash loan (a loan that is paid back in the same transaction). So instead, your Safe owns a DeFiLoops account: nothing is installed on the Safe, it signs with its usual number of owners, and the agent can reach only the operations your account allows, with a daily limit per token if you set one. Safe is the most widely held smart wallet in DeFi, so “can a Safe just use this directly?” is the first question anyone asks. Yes for batched calls, with nothing installed on it. No for flash loans, which a Safe cannot take without installing a module.

Batched calls: yes

A Safe can run a batch of calls with nothing installed on it. It needs no module, extension or setup.

Flash loans: no

A Safe cannot take a flash loan without installing a module. There is no way around this.
Everything below was measured against a real Safe on Base.

The half that works

The owners sign one ordinary transaction that runs a batch in the Safe’s own context. Everything the batch touches sees the Safe as the caller, and the Safe’s own storage is what changes. Safe’s own batching contract works the same way, which is why “batch these calls” needs no setup.

The half that does not

The protocol calls back. Every flash loan is two steps. The protocol sends the money, then calls a function on the recipient to let it do the work before repaying. That callback is a fresh call into the Safe, for a function the Safe does not have. The language does not care that a batch is still running further down the stack. The call arrives from outside, and the Safe forwards it to its fallback handler. A fallback handler cannot help either. The Safe reaches its handler with a plain call, not with the borrowing mechanism that shares its context. The handler runs in its own context. Even a handler that implemented the callback perfectly would be a different contract, holding no tokens, with no authority over the Safe.
Naming a different recipient does not rescue this. Flash loan protocols let you name who receives the callback, so a helper contract can take it. That helper then has no authority over the Safe, which is the thing you needed.Nor can a permission-based helper substitute. Given an allowance, a helper can supply and repay on a Safe’s behalf, because those accept “on behalf of”. It can never withdraw, because withdrawal acts on the caller’s own position, and it cannot borrow without a separate delegation. Withdrawing collateral is half of every unwind, so this route cannot work.

Which leaves three options

If the position must live inside the Safe itself, a module is the only way. That is a real cost. A module keeps full power for as long as it is installed, and that power is not scoped per operation. It is also one more contract inside the trust boundary of a wallet whose whole appeal is a small one.

What we do instead

The Safe owns an account. Nothing is installed on the Safe. The position lives in the account, and the Safe is its owner. This works because of one substitution. The standard owner check recovers a signer from the signature and compares it to the owner. A Safe’s address can never be the answer to a recovery, because a Safe has no private key. Our checker asks the owner instead: it hands the signature to the owner contract and accepts whatever that contract says. A contract owner then answers under its own rules, which for a Safe means its threshold. Two further properties matter as much as the delegation:
  • It does not fail on a long signature. Standard recovery rejects anything that is not one signature’s length, and a Safe’s multi-owner signature is one length per owner. A failure inside validation surfaces as a rejected transaction rather than a clean “wrong signature”.
  • It falls back to standard recovery when the owner has no code, so an ordinary wallet keeps working. Our checker is a superset of the standard one, which is what lets an account be re-owned by a Safe later without changing which checker is in charge.
It also keeps the owner’s direct route alive. A Safe can drive the account with no helper service and no balance in the account, because the Safe proves who it is by making the call.

What this gets you that a module does not

The Safe delegates bounded authority rather than total authority. The agent can reach only the operations your account allows, each with its own checks, and you can set a daily limit per token. If the owner did not authorise an operation, the operation itself refuses it. A module cannot be limited this way. → Your account and your keys New accounts are also proved accounts, and that holds for a Safe-owned account too. A plan can pay its proceeds back to your Safe, because the Safe is an owner that can act for itself. An address whose key was discarded cannot.

What it costs

A Safe owner gets a different address from a plain wallet. The kind of owner is part of what the address is worked out from. The console reads your wallet and picks the setup, so you do not choose it. There is no migration for an address already published.
It has two more costs:
  • Signing is two layers deep. The account wraps the message in its own envelope, and the Safe wraps that in another. Anything signing for the account must reproduce both.
  • The checker is deliberately minimal. It has no defence against the same message being valid for two accounts, so a Safe owning two accounts answers the same message for both. It has no owner rotation, and no guard against an owner contract that later upgrades into something else.
It is deployed permanently, and cannot be replaced, unlike every other shared contract here. Whoever could replace an owner checker could authorise anything on every account that uses it, which is a larger power than anything else here grants. We chose to make that “nobody”, so a bug is fixed by deploying a new checker.