Skip to main content

Wrapper Integration

Generalized wrappers enable custom logic to execute surrounding CoW Protocol settlements. This guide covers both using existing wrappers in your orders and building new wrapper contracts.

Choose your path:


For Wrapper Developers

This section covers building new wrapper contracts from scratch.

Overview

To build a wrapper, you will:

  1. Inherit from the CowWrapper abstract contract
  2. Implement _wrap() with your pre/post-settlement logic
  3. Implement validateWrapperData() for input validation
  4. Test thoroughly on testnets
  5. Review the Implementation Requirements to ensure your wrapper meets the acceptance requirements
  6. Submit for allowlist approval by the CoW Protocol team

Read more on the details of creating a wrapper from the wrapper contract information page.


For Order Creators and Frontend Developers

This section shows you how to use existing wrappers in your orders and integrate wrapper support into your application.

Adding Wrappers to Orders

To use a wrapper in your order, add it to the appData when creating the order:

AppData Structure

interface WrapperCall {
target: string; // Wrapper contract address (must be allowlisted)
data?: string; // Optional hex-encoded wrapper-specific data
isOmittable?: boolean; // Whether solver can skip this wrapper (default: false)
}

Fields:

  • target (required): Address of the allowlisted wrapper contract
  • data (optional): Hex-encoded data specific to the wrapper. Can be empty or omitted if the wrapper doesn't need custom data.
  • isOmittable (optional): Defaults to false
    • false = Solver MUST execute the wrapper with exact data or be slashed
    • true = Solver MAY skip the wrapper if they find a better solution

Example: Using the CoW SDK

import { OrderBookApi, OrderQuoteRequest, OrderCreation } from '@cowprotocol/cow-sdk'

// Create order with wrapper
const orderCreation: OrderCreation = {
// ... standard order fields (sellToken, buyToken, amounts, etc.)

appData: {
// ... other appData fields
wrappers: [
{
target: "0x1234...", // Flash loan wrapper address
data: "0xabcd...", // Encoded flash loan params
isOmittable: false // Must execute
}
]
}
}

// Submit order
const orderId = await orderBookApi.sendOrder(orderCreation)

Example: Multiple Wrappers (Nested)

You can chain multiple wrappers in a single order:

appData: {
wrappers: [
{
target: "0x1111...", // Flash loan wrapper
data: "0xaaaa...",
isOmittable: false
},
{
target: "0x2222...", // Leverage wrapper
data: "0xbbbb...",
isOmittable: false
}
]
}

The wrappers execute in sequence: Wrapper1 → Wrapper2 → Settlement → Wrapper2 (post) → Wrapper1 (post). Note that wrappers from other users' orders may be interspersed, though this should generally not affect the execution of the order.

Validating Wrapper Configuration

Before submitting an order, you can confirm the wrapper encoding is valid using CowWrapperHelper:

// On-chain validation (via Ethers/Viem)
const helper = new ethers.Contract(HELPER_ADDRESS, HELPER_ABI, provider)

const isValid = await helper.verifyAndBuildWrapperData([
{
target: '0xSomeAddress',
data: '0xSomeData'
},
{
target: '0xSomeAddress2',
data: '0x'
}
])
// Returns encoded chainedWrapperData if valid, reverts if invalid

This checks:

  • All wrappers are allowlisted
  • Each wrapper can parse its data successfully

The CoW Wrapper Helpers contract is deployed via CREATE2, and is being rolled out to the following addresses on each network supported by CoW:

  • Production: 0x8C8f88F3081A7d54fCbC2Bd7C6Cf5E9Fc26e30E9
  • Staging: 0xfd1a35C8E7AEC58a4bB6AeDca0B2Bf9c9Be9E07F

For Solvers

This section explains how to execute settlements that include wrapper contracts as part of your solver implementation.

Detecting Wrapper Orders

Wrappers are specified in the order's appData under the wrappers field:

{
"wrappers": [
{
"target": "0x1234...",
"data": "0xabcdef...",
"isOmittable": false
}
]
}

Fields:

  • target: Address of the wrapper contract (treat as opaque - don't parse)
  • data: Wrapper-specific data (treat as opaque - don't parse)
  • isOmittable: Whether the target and data must be executed unmodified as part of the order execution

Solver Requirements

1. Execute Non-Omittable Wrappers

Orders with "isOmittable": false MUST be executed with the specified wrapper. You may be slashed for not doing so.

If "isOmittable": true, you MAY skip the wrapper if you find a better solution without it.

2. Verify Wrapper Authentication and Simulate

All approved wrappers will be approved by the DAO and registered in GPv2AllowlistAuthenticator. It is advised to verify this is the case before attempting to process a wrapper order.

Additionally, wrappers define additional operations that may revert, so it is strongly recommended to simulate the settlement transaction while including the wrapper call to verify its viability. The call trace can also be inspected for any unusual behavior.

warning

The wrapper will be directly called from the solver address and will mediate the settlement. Since the data is user-supplied, it may be malicious.

3. Include Wrappers in the Solution

Whether using the CoW Protocol-provided driver or your own, ensure wrapper information flows from the auction to your final settlement transaction. This data should be passed unmodified from the orders in the auction to the final Solution submitted to the API.

Encoding Wrapper Settlements

info

If you're using the driver provided by CoW Protocol, you can skip this section - the driver handles encoding automatically.

Manual Encoding

To execute a settlement with wrappers:

1. Change Transaction Target

Your transaction should call wrappedSettle() on the first wrapper (not the settlement contract):

// Without wrapper
tx = {
to: SETTLEMENT_CONTRACT,
data: encodeSettle(...)
}

// With wrapper
tx = {
to: wrappers[0].target, // First wrapper address
data: encodeWrappedSettle(...) // See below
}
2. Construct settleData Parameter

The settleData parameter is the exact calldata you would send to GPv2Settlement.settle(), including the 4-byte function selector:

const settleData = settlementContract.interface.encodeFunctionData("settle", [
tokens,
clearingPrices,
trades,
interactions
]);
// This is your settleData - unchanged from normal settlement
3. Encode the chainedWrapperData Parameter

Build chainedWrapperData according to the Calldata Encoding Specification.

4. Call wrappedSettle
const tx = {
// The `chainedWrapperData` does not include the first wrapper to call,
// so it is supplied here as the _target_ of the settlement call.
to: wrappers[0].target,
data: wrapperContract.interface.encodeFunctionData("wrappedSettle", [
settleData, // From step 2
chainedWrapperData // From step 3
])
}

Using CowWrapperHelper

CowWrapperHelper is a read-only periphery contract that can be called to validate many important points prior to execution. See the periphery contract documentation.

Accumulating Wrappers in Solutions

Using CoW-Provided Driver

If you're using the CoW Protocol-provided driver, wrappers are handled automatically. Just ensure your solver process includes wrapper information in the solution output.

Custom Implementation

If implementing your own solver:

  1. Collect wrappers from orders: As you process orders in an auction, collect all wrappers arrays from order appData
  2. Aggregate for batch: Combine wrappers needed for all orders in the settlement batch
  3. Include in solution: Add aggregated wrappers to your solution structure
  4. Encode transaction: Use the encoding algorithm above to construct the final transaction

Example (conceptual):

// Process auction
const solution = {
orders: [...],
wrappers: [] // Collect here
};

for (const order of auction.orders) {
if (order.appData.wrappers) {
// Add wrappers needed for this order
solution.wrappers.push(...order.appData.wrappers);
}
}

// Encode final transaction using the manual encoding steps described above:
// 1. Set tx target to solution.wrappers[0].target
// 2. Build settleData from your normal GPv2Settlement.settle() calldata
// 3. Build chainedWrapperData per the Calldata Encoding Specification in the reference docs
// 4. Call wrappedSettle(settleData, chainedWrapperData) on the first wrapper
const tx = {
to: solution.wrappers[0].target,
data: wrapperContract.interface.encodeFunctionData("wrappedSettle", [
settleData,
chainedWrapperData
])
};

Testing and Validation

Gas Estimation

Account for wrapper gas overhead in your bids — see Gas Overhead for benchmarks and scaling factors. The easiest way to estimate overhead for a specific wrapper is to simulate the wrapper transaction against an empty settlement.

Common Issues

Issue: "Not authorized" error

Cause: Wrapper is not allowlisted in GPv2AllowlistAuthenticator

Solution: Verify wrapper is DAO-approved before including in settlement

Issue: Settlement reverts in wrapper

Cause: Incorrect encoding or wrapper-specific validation failure

Solution:

  • Verify settleData is identical to what you'd send to GPv2Settlement.settle()
  • Check chainedWrapperData encoding follows specification exactly
  • Use CowWrapperHelper for validation

Solver Resources

Documentation