· 13 min read

From Scripts to Programs: How Smart Batching Evolves On-Chain Execution

From Scripts to Programs: How Smart Batching Evolves On-Chain Execution

A technical comparison of Weiroll and ERC-8211 — and why declarative execution is the future of DeFi.


If you have ever tried to chain a swap into a lending deposit in a single transaction, you already know the problem. You sign a batch that says "swap 100 USDC for WETH, then supply 0.05 WETH to Aave." By the time the transaction lands, the swap only returned 0.0495 WETH. Your hardcoded 0.05 amount fails. The batch reverts. Your gas is gone.

This is not a niche edge case. It is the default experience of multi-step DeFi on Ethereum today. Swap outputs depend on price impact, slippage, and MEV. Lending withdrawals depend on variable share rates. Bridge deliveries carry unpredictable fees. Every parameter that touches live state becomes a guess the moment you sign.

Two projects attack this problem from fundamentally different angles. Weiroll, the 2021 pioneer, introduced a lightweight virtual machine for chaining contract calls on the EVM. ERC-8211, a 2026 standards-track proposal from Biconomy and the Ethereum Foundation, introduces "smart batching" — a declarative encoding where each parameter describes how to obtain its value at execution time and what conditions that value must satisfy.

This article compares them in detail: how they work under the hood, where they diverge, and why the difference matters for anyone building or using DeFi.


Weiroll: The Pioneer

Weiroll was one of the earliest serious attempts to move beyond simple Multicall. Where Multicall lets you batch independent calls, Weiroll lets you chain them — the return value from call A can become the input to call B. In doing so, it established an entirely new primitive in the Ethereum developer toolkit: composable on-chain scripts.

How it works

Weiroll is a tiny on-chain virtual machine. You give it two things: an array of commands (each packed into 32 bytes) and an array of state values (your working registers). The VM runs through the commands one by one. Each command says: "call this function on this contract, pull inputs from these state slots, write the output to that state slot."

Command (bytes32):
┌───────┬─┬───────────┬─┬───────────────────────────────────────┐
│  sel  │f│    in     │o│              target                   │
└───────┴─┴───────────┴─┴───────────────────────────────────────┘
  4-byte   1  6 bytes  1         20-byte address
selector flag indices  out

The beauty is its simplicity. In about 200 lines of Solidity, Weiroll can chain arbitrary contract calls, pass return values between them, and handle both fixed-length and variable-length arguments. The weiroll.js TypeScript SDK gives developers a Planner abstraction:

const planner = new weiroll.Planner();
const wethOut = planner.add(router.exactInputSingle(usdc, weth, 500, amount, 0));
planner.add(aavePool.supply(weth, wethOut, self, 0));
const { commands, state } = planner.plan();

The Planner handles state slot assignment so developers don't have to think in register indices. Several production systems have adopted Weiroll, including Enso Finance (for their "unified DeFi API") and Royco Protocol (for on-chain transaction "recipes").

Where Weiroll shines

Gas efficiency. Weiroll's encoding is remarkably compact. One command is one bytes32. The CommandBuilder library uses assembly-level memory operations, the identity precompile for memory copies, and avoids dynamic allocation wherever possible. For raw operation chaining without additional safety logic, it is hard to beat on gas.

Minimal surface area. The entire VM is about 200 lines of Solidity. The CommandBuilder library is another 150. There is very little code to audit, and the code that exists is straightforward. ChainSecurity's audit concluded the codebase provides "a good level of security" for functional correctness and memory consistency. The small footprint also means fewer places for bugs to hide.

True generality. Weiroll is not opinionated about what you chain. DeFi swaps, NFT mints, governance votes, arbitrary contract interactions — if it has a function selector, Weiroll can call it and pipe the output forward. It supports DELEGATECALL, CALL, STATICCALL, and CALL with value, covering every EVM call type. The subplan mechanism even handles flash-loan-style callbacks where a nested sequence must execute inside a callback frame.

Proven in production. Weiroll is not theoretical. Enso Finance processes real DeFi flows through it. Royco Protocol uses it to define on-chain incentive "recipes." These are not toy deployments — they handle real value and have weathered the adversarial environment of mainnet. That production track record matters when evaluating any on-chain primitive.

Low barrier to adoption. Any contract that can delegatecall can use the Weiroll VM. There is no need to implement interfaces, register modules, or integrate with account-abstraction standards. For teams that just need operation chaining and nothing else, Weiroll's lack of ceremony is a feature.

Where it meets its limits

Weiroll was built as general-purpose plumbing, and it acts like it. There is no branching. No looping. No built-in safety checks. If the swap returns less than you expected, the next call either works or reverts — there is no way to assert "the output must be at least X" without deploying a custom assertion contract and threading it into the command chain.

The on-chain encoding is opaque. A bytes32[] command array and bytes[] state array carry no semantic information. An auditor examining the calldata sees packed bytes and state slot indices. Determining what a Weiroll program actually does requires decoding each command, cross-referencing ABIs, and mentally simulating the state mutations. ChainSecurity, which audited the Enso-Weiroll implementation, flagged the "Complexity of Commands Effect Evaluation" as a fundamental concern inherent to the design.

And cross-chain? Weiroll has no concept of it. It is a single-transaction, single-chain VM. If you want to coordinate across chains, you build the orchestration yourself.

These are not failures of design — they are consequences of scope. Weiroll set out to be a minimal, efficient operation chainer, and it succeeded. The question is whether that scope is sufficient for what the ecosystem demands in 2026.


ERC-8211: Smart Batching

ERC-8211 starts from a different premise. Instead of asking "how do we chain function calls efficiently?" it asks: "what does a DeFi execution plan actually need to declare?"

The answer, according to the standard's authors, is three things:

  1. How to get each value — not just what the value is, but how to obtain it at execution time
  2. What the value must satisfy — inline constraints that revert the batch if violated
  3. Where to route the value — whether it becomes a call target, ETH amount, or calldata

The three primitives

Runtime parameter injection. Each parameter carries a "fetcher type" that tells the executor how to resolve the value on-chain:

Instead of writing supply(0.05 WETH) and hoping, you write supply(BALANCE(WETH)). The executor calls IERC20(WETH).balanceOf(self) at execution time and gets the exact number.

Pre-and-post assertions. Each resolved value can carry inline constraints — EQ, GTE, LTE, IN — that are checked on-chain before the value is routed. An entry with target = address(0) becomes a predicate entry: a pure boolean gate that reverts the batch if conditions fail.

This is how you get MEV protection without writing Solidity: assert that the swap output is greater than or equal to your minimum acceptable amount. If a sandwich attack compresses the output below that threshold, the batch reverts atomically. No custom contract. No audit cycle.

Multi-transaction context. A shared Storage contract lets entries write values that later entries — or even subsequent UserOperations — can read. Data flows between steps without custom contracts.

What authoring looks like

The TypeScript SDK compiles high-level intent into the on-chain encoding:

const batch = smartBatch([
  swap({ from: WETH, to: USDC, amount: fullBalance() }),
  predicate({ balance: gte(USDC, account, 2500e6) }),
  supply({ protocol: "aave", token: USDC, amount: fullBalance() }),
  stake({ token: aUSDC, amount: fullBalance() }),
]);

Four steps. Every amount resolves dynamically. An inline predicate ensures the swap returned enough. No hardcoded values. No leftover dust. No Solidity.


Where They Diverge

Readability: packed bytes vs. self-describing data

Weiroll's on-chain representation is a packed binary array. It is compact and gas-efficient, but understanding it requires specialized tooling. A wallet displaying a Weiroll transaction to a user would show... a hex blob.

ERC-8211's encoding is structured data. Each ComposableExecution entry contains typed fields: fetcher types, routing destinations, constraint arrays. A wallet or block explorer can reconstruct what the batch intends to do from the encoding alone — no external ABI lookups, no heuristic analysis.

This might sound like an aesthetic concern. It is not. Readability directly determines whether automated tools can analyze batches, whether wallets can show meaningful previews, and whether auditors can verify safety. The more information the encoding itself carries, the less trust the end user must place in opaque tooling.

Static analysis: can you verify it without running it?

Weiroll programs are bytecode for a custom VM. To statically analyze one, you need a symbolic execution engine that understands the command encoding, the state array mutations, and the ABIs of every target contract. This is achievable — people build symbolic analyzers for EVM bytecode all the time — but it is not easy, and the lack of semantic metadata in the encoding means the analyzer must infer intent from low-level operations.

ERC-8211 batches are declarative metadata. Each parameter announces its resolution strategy and its constraints upfront. A static analyzer can inspect an InputParam and immediately know: "this reads the USDC balance of the sender, routes it to the third calldata position, and asserts it must be ≥ 2500e6." No inference required. The intent is in the encoding.

This enables a new category of tooling: intent-level static analysis. Not just "will this bytecode revert?" but "does this batch's declared intent match the user's actual goal?" Relayers, bundlers, and AI agents all benefit from this directly.

DeFi-first vs. general-purpose

Weiroll is a general-purpose operation chainer. It can chain any contract calls — DeFi swaps, NFT mints, DAO governance, custom protocol interactions — without caring what the calls do. This generality is genuinely valuable: Weiroll works as a universal "glue" layer for any on-chain workflow, and its neutrality means it will never be limited by the primitives its designers chose to include. If you can express it as a sequence of contract calls, Weiroll can execute it.

The trade-off is that every DeFi-specific need (balance queries, slippage checks, oracle gates) requires deploying custom helper contracts and auditing them. Weiroll gives you the plumbing; you build the fixtures.

ERC-8211 takes the opposite bet. It is built for DeFi from the ground up. The BALANCE fetcher, the constraint system, the predicate entries, the Storage contract — these are the specific primitives that real DeFi flows have demanded for five years, codified directly into a standard encoding. While ERC-8211 can technically call any smart contract (it is not restricted to DeFi), its design choices are deliberately optimized for the patterns that DeFi demands most.

Consider what it takes to implement "send my full token balance with slippage protection" in each:

Weiroll:

  1. Deploy a helper contract that calls balanceOf and returns the balance
  2. Deploy an assertion contract that compares two values and reverts if the check fails
  3. Chain: helper call → swap call → assertion call → supply call
  4. Audit both custom contracts
  5. Manage state slots manually for all intermediate values

ERC-8211:

  1. Set the swap amount's fetcher to BALANCE
  2. Add a GTE constraint to the swap output parameter
  3. Set the supply amount's fetcher to BALANCE
  4. Done. No deployment. No audit of custom contracts.

For teams building general-purpose tooling or non-DeFi workflows, Weiroll's unopinionated design may still be the better fit. For DeFi-specific flows — which constitute the overwhelming majority of multi-step on-chain execution today — ERC-8211 removes an entire category of infrastructure work.

Cross-chain: absent vs. native

This is perhaps the starkest difference.

Weiroll has no cross-chain model. It is a single-chain VM. If you need a multi-chain flow — say, unwinding a position on Base and redeploying it on Ethereum — you build separate Weiroll programs for each chain and orchestrate them externally.

ERC-8211 treats cross-chain orchestration as a first-class concern. A user signs a single Merkle root covering batches on multiple chains. Each chain-local batch executes independently. The Ethereum-side batch includes predicate entries that gate on cross-chain state: "execute this only when my WETH balance exceeds 2 ETH" (meaning the bridge from Base has delivered).

The specification is explicit about being credibly neutral to the interoperability layer. The predicates observe state, not mechanism. Whether the bridge is Optimism's native bridge, Across, ERC-7683, or LayerZero, the batch just waits for the balance to appear. This is a powerful separation of concerns: the execution plan doesn't care how assets arrive, only that they did.

Security model: implicit vs. explicit

Weiroll's security story is a mixed bag of genuine strengths and structural limitations. On the positive side, its small codebase (~350 lines of Solidity) means a relatively small attack surface. ChainSecurity's audit confirmed "high security" for functional correctness and memory consistency. The simplicity of the execution model — sequential commands, no branching, no reentrancy patterns — makes the VM itself predictable. And Weiroll supports all four EVM call types, so developers can choose STATICCALL for read-only operations or CALL for external interactions when DELEGATECALL is too permissive. (Enso's production deployment, for instance, disabled DELEGATECALL entirely and runs on CALL only.)

The structural limitation is that Weiroll has no built-in validation layer. All safety must come from the called contracts themselves or from custom wrapper contracts. The encoding carries no information about what invariants the programmer expects to hold. This puts the burden of safety entirely on the developer and makes it harder for external tools (wallets, bundlers, auditors) to reason about batch safety without deep context.

ERC-8211 inverts this model. It uses standard CALL semantics and provides inline constraints as a first-class safety mechanism. Each resolved value is validated against its predicates before routing. The safety invariants are part of the encoding itself — visible to wallets, analyzable by tools, verifiable on-chain.

This shift — from "safety is the developer's problem" to "safety is encoded in the batch" — is arguably ERC-8211's most important design decision. It does not replace the need for careful development, but it provides a structural layer of protection that is absent in systems where safety is entirely external.


The Gas Question

Weiroll is leaner per-command, and this is not a trivial advantage. A packed bytes32 command versus a structured ComposableExecution struct — Weiroll wins decisively on raw encoding size and calldata cost. For L2 chains where calldata compression is a major cost factor, or for simple operation chains where safety checks are handled by the target contracts, Weiroll's encoding efficiency translates directly to lower costs. If you are chaining three calls that don't need inline assertions, Weiroll will almost certainly be cheaper.

The calculus shifts for production DeFi flows. The moment you add balance assertions, slippage protection, or oracle gating — which most real flows need — you're deploying and calling additional helper contracts in Weiroll. Those cross-contract calls add gas that erodes the encoding advantage.

ERC-8211's inline constraints avoid the cross-contract call overhead for safety checks. For production-grade DeFi flows with proper safety, the total gas cost is competitive. The right framing is not "which is cheaper?" but "which gives you more for your gas?" — and for DeFi flows that need runtime resolution and safety guarantees, ERC-8211's per-gas value proposition is strong.


Compatibility and the Account-Centric Vision

Weiroll's compatibility model is simple: if your contract can delegatecall the VM, you can use it. This works, and its simplicity is an advantage for quick integration. But it is agnostic to the account layer — Weiroll does not know or care whether it is running inside an ERC-4337 smart account, an ERC-7702 delegated EOA, or a raw contract. Integrators build their own adapters.

ERC-8211 takes a fundamentally different approach. It is account-centric by design — the standard defines not just an encoding, but a single interface (IComposableExecution) with normative integration patterns for every major smart account architecture:

It is also compatible with ERC-4337 smart accounts, EIP-5792 wallet_sendCalls, and ERC-7683/7786 interop layers.

Alternatively, if the user is starting from a non-7702 EOA account - meaning a completely regular EOA - they can use ERC-8211 via a passthrough smart account.

Preparing for native account abstraction: EIP-8141

This account-centric positioning becomes even more significant when you look at where Ethereum itself is headed. EIP-8141 — the Frame Transaction proposal authored by Vitalik Buterin, lightclient, and the ERC-4337 team — introduces a new transaction type (0x06) that makes account abstraction a first-class protocol feature. Instead of relying on a single ECDSA signature, Frame transactions split validation, execution, and gas payment into separate "frames," each executed by arbitrary EVM code.

Under EIP-8141, every account becomes programmable. Validation can use any cryptographic scheme (including post-quantum). Gas can be paid by third parties or in ERC-20 tokens. Execution frames run with configurable caller contexts (ENTRY_POINT, SENDER, or DEFAULT).

ERC-8211 is explicitly designed to work as the execution payload within this architecture. A Frame transaction's SENDER-mode frame can invoke executeComposable() on the sender's account, running a full smart batch with runtime-resolved parameters and inline constraints — all inside Ethereum's native transaction format. The predicate model maps naturally to Frame transactions: a VERIFY frame handles authorization, while SENDER frames execute the composable batch. No bundler infrastructure. No mempool workarounds. Native protocol-level account abstraction, with smart batching as the execution layer.

This is not speculative compatibility. ERC-8211's PR (#1638) lists EIP-8141 as a compatibility target, and lightclient — a co-author of EIP-8141 — has reviewed the ERC-8211 specification directly. The two standards are being designed in awareness of each other.

Weiroll, as a general-purpose VM from 2021, predates this entire account-abstraction stack and has no formal relationship to any of these standards. It can certainly be wrapped into adapters for each, but the wrapping is left as an exercise for the integrator.

The implication is clear: ERC-8211 is not just solving today's DeFi execution problems. It is positioning composable execution as a first-class citizen of Ethereum's native account-abstraction future.


The Bigger Picture

Weiroll deserves more credit than it often receives. Before Weiroll, the Ethereum execution model was simple and limiting: one transaction, one function call. Multicall improved this by batching independent calls, but it could not express dependencies between them. Weiroll broke that barrier. It proved that a lightweight on-chain VM could thread return values between arbitrary contract calls, creating composable programs from individual operations. It did this in minimal code, with impressive gas efficiency, and it shipped to production. Enso, Royco, and others built real businesses on it. The concept of "on-chain scripting" that Weiroll introduced has influenced every composable execution system that followed.

For use cases that value raw simplicity — a minimal VM, maximum gas efficiency, zero opinions about what you chain — Weiroll remains an excellent tool. It will likely continue to serve systems that have built around it and teams that need a thin, general-purpose execution layer without the weight of a formal standard.

But the landscape has changed around it. DeFi is multi-chain by default. Account abstraction has matured across multiple competing standards and is heading toward native protocol support with EIP-8141. AI agents are emerging as on-chain actors that need verifiable, constraint-bounded execution. The demands of 2026 are fundamentally different from 2021.

ERC-8211 absorbs Weiroll's core insight — chain calls with data dependencies — and wraps it in a system designed for how DeFi actually works today and where Ethereum is heading tomorrow:


ERC-8211 is in Draft status. The specification is available at erc8211.com and the ERC pull request at ethereum/ERCs #1638. Weiroll's source is at github.com/weiroll/weiroll with the JS SDK at weiroll.github.io/weiroll.js.