Why Sign Twice?
How Sonic's Bundled Transactions enable single-signature workflows for complex onchain actions.
Bundled Transactions on Sonic V2.2 solve the partial execution problem: related transactions succeed or fail together, with no unrelated activity inserted between them. That is the core capability, covered in depth in "Bundled By Default."
But there is a second question that bundles open up, one that gets closer to what users actually feel.
When a flow involves five steps, why does the user sign five times?
The Signing Problem
Fate-sharing and non-interleaving guarantee that a multi-step operation completes cleanly or rolls back entirely. That is a major structural improvement. But in the default bundle workflow, each transaction in the bundle still requires its own signature from its respective signer.
For a two-step flow (approve + swap), two signatures is manageable. For a five-step flow (approve, swap, deposit, create position, confirm), five signatures starts to feel like the product is asking permission at every step instead of letting the user act.
The signatures are not pointless. Each one authorizes a specific transaction. But from the user's perspective, they authorized the outcome when they clicked the button. Everything after that is the system asking for confirmation of steps the user did not choose individually.
The Delegate Pattern
Sonic's bundle architecture enables a pattern that compresses multi-step workflows into a single wallet interaction. It works like this:
The application creates a temporary delegate account. This is a throw-away key pair, generated by the application, that exists only for the duration of this operation. The delegate has no assets and no history.
The application prepares the full sequence of transactions needed to complete the user's intent. Only the first transaction requires the user's signature: a transfer of the necessary funds to the delegate account. The remaining transactions (the purchases, swaps, or transfers the workflow requires) are signed by the delegate. The final transactions in the sequence transfer the results back to the user.
All of these transactions are wrapped in a single atomic bundle.
The user signs once. The bundle either completes in full (funds move to the delegate, the delegate executes the operation, the results return to the user) or the entire sequence rolls back and the user's funds never leave their wallet.
A Concrete Example
A user wants to purchase five collector items on a marketplace. Each item costs $20. The user wants all five or none. They are not interested in ending up with three out of five.
Without the delegate pattern:
The application creates a bundle with five purchase transactions. The user signs each one individually, with the guarantee that all five succeed or all five roll back. The atomicity is there, but the user is presented with five signature prompts.
With the delegate pattern:
The application creates a temporary account and prepares eleven transactions:
- The user transfers $100 to the delegate account (user signs this one)
- Five transactions where the delegate purchases each item
- Five transactions where the delegate transfers each purchased item back to the user
Transactions 2 through 11 are signed by the delegate key, which the application controls. The user never sees them.
All eleven transactions are bundled with AllOf semantics. If any purchase fails, the entire bundle rolls back. The user's $100 never moves. If all five purchases succeed, the items are transferred to the user's wallet in the same atomic execution.
One signature. Five items. All or nothing.
Why This Is Safe
The immediate question: if the application controls the delegate account and signs transactions on its behalf, what prevents the application from doing something the user did not intend?
The answer is in how bundle consent works.
The user's transaction (the $100 transfer) is marked as bundle-only and tagged with the hash of the full execution plan. That execution plan specifies every transaction in the bundle, in order, with their exact parameters. The user's funds can only move as part of that exact plan. If the application changes any transaction, adds a step, removes a step, or reorders the sequence, the execution plan hash changes and the user's signed transaction becomes invalid.
The user is not trusting the application to behave correctly. They are signing a cryptographic commitment to a specific, verifiable execution plan. The plan is the guarantee.
Additionally, because the delegate account is created fresh for each operation and has no persistent assets, there is no residual risk after the bundle executes. The delegate key can be discarded. There is nothing to steal, nothing to exploit, and no ongoing delegation to revoke.
Where This Works
The delegate pattern works cleanly for workflows where every step produces a transferable result. The delegate executes the operations, and the outputs (tokens, NFTs, or other transferable assets) move back to the user in the final steps of the bundle.
This covers a significant range of use cases:
Token operations. Batch swaps, multi-hop routing, aggregator flows, yield harvesting where the output is a token. The delegate swaps or collects, the results transfer back.
NFT and collectible operations. Batch purchases, batch listings, or batch transfers where the user wants all-or-nothing semantics without signing each item individually. The NFT example above is the cleanest illustration.
Multi-asset portfolio moves. Selling out of several positions and buying into several new ones, where every step produces a token the delegate can transfer back. One authorization from the user, one atomic rebalance.
Where It Does Not
The delegate pattern has a real constraint: it depends on the results being transferable to the user after execution.
When a protocol assigns ownership based on msg.sender, the delegate pattern creates a problem. If the delegate account opens a lending position, that position belongs to the delegate, not to the user. The delegate gets discarded after the bundle completes. The position is orphaned.
This affects any workflow where the final state is a protocol-owned position rather than a transferable asset: lending positions, LP positions, staking entries, or any contract that records the caller as the owner.
There are two paths forward for these cases.
Protocols that support "on behalf of" parameters can work with the delegate pattern today. Some DeFi protocols already include an explicit beneficiary field in their supply, borrow, or deposit functions, allowing the delegate to create a position owned by the user even though the delegate is the caller. Where this parameter exists, the delegate pattern works as described.
Protocols that don't should use standard multi-sign bundles instead. The user signs each transaction in the bundle directly, so msg.sender is always the user's own address. Atomicity and non-interleaving still apply. The only difference is the number of wallet interactions.
This is an honest boundary. The delegate pattern is not universal. It is a powerful optimization for a specific (and common) class of workflows. For everything else, standard bundles already solve the partial execution problem. The user signs more, but the execution is still atomic.
Over time, this boundary may shrink. "On behalf of" is already a recognized pattern in protocol design, and as bundled execution becomes a standard primitive on Sonic, there is a natural incentive for ecosystem protocols to support it. Every protocol that adds beneficiary support unlocks single-signature flows for its users. The delegate pattern gets stronger as the ecosystem adopts it.
What This Does Not Replace
The delegate pattern is not a substitute for direct signing in every context. There are workflows where the user should sign each step individually, either because the steps are genuinely independent decisions or because the regulatory or compliance context requires explicit per-action authorization.
It is also not a replacement for smart wallets or account abstraction. Those serve different use cases (programmable account logic, social recovery, session keys). The delegate pattern is narrower: it compresses a known sequence of dependent steps into a single user interaction using standard EOA infrastructure.
The pattern is an application-level design choice built on top of Sonic's protocol-level bundle primitive. The protocol provides atomicity and consent verification. The application decides whether and how to use delegation to simplify the signing experience.
From Five Signatures to One
The question "why sign twice?" is really a question about where the boundary sits between user intent and execution detail. When a user clicks "buy the set" or "swap and deposit," they are expressing a single intent. The transactions underneath that intent are implementation details that the product is leaking to the user.
Sonic V2.2 provides two layers of improvement. Bundled transactions ensure the implementation details either all complete or all roll back. The delegate pattern, built on top of bundles, compresses the user's involvement to a single authorization for workflows that produce transferable results.
For position-creating workflows, standard bundles still deliver atomicity with direct signing. For everything that moves assets, the delegate pattern takes it further.
Why sign twice?
For a growing number of workflows, you won’t have to.